As for the credits, it's definitely not my display as it occurs on real hardware as well (GBA SP and GBC) and does NOT occur when I play the rom in SGB mode on my CRT.
Wanted to follow up on this as I believe I have found and fixed the problem. It all comes down to the way the credit sequence itself is coded. Specifically, it's the way the pokemon silhouettes are scrolled to the left.
This function here in engine\HoF_room_pc.asm does the heavy lifting of the scrolling.
--The "h" register contains the new x-position to scroll to (one 8-pixel tile to the left).
--The "l" register contains a vertical line value (usually 32 or 112).
--rLY is a hardware pointer that tells you which vertical line the LCD Driver is currently drawing.
--rSCX is "Scroll X"; a hardware pointer that lets you load the BG tile map to the screen at an x-coordinate offset.
ScrollCreditsMonLeft_SetSCX:
ld a, [rLY]
cp l
jr nz, ScrollCreditsMonLeft_SetSCX
ld a, h
ld [rSCX], a
.loop
ld a, [rLY]
cp h
jr z, .loop
ret
So what this does is it first waits until the gameboy is drawing a specific vertical line on the screen given by "l". Then it sends the new x-position to scroll to directly to the gameboy hardware. Finally it waits until the first line of the new scroll position is being drawn before returning.
This is very different from the rest of the game engine which usually loads new scroll positions into temporary addresses that are involved in automatic update functions. It's normal to write a new scroll position into an hram address called hSCX and then delay by one frame so the Vblank function updates rSCX automatically. But the director wanted the Pokemon silhouettes to scroll by very fast! Doing it the traditional way with frame delays and/or waiting for the Vblank function would create a very smooth and much slower effect. Doing it directly like this gets the fast scrolling that is desired.
There's just one problem though. Waiting for the desired vertical line to be reached does not stop the gameboy from entering its vblank period. This "vertical blank" period is built into the hardware, and it is a period between drawing the final vertical line of the current frame where data is prepared and transferred before the LCD starts drawing the first line of the next frame. This is where graphics data is normally transferred to the LCD driver so as to prevent split images being drawn to a single frame. Whatever x-position value is stored in hSCX is gets transferred to rSCX every time Vblank is entered; that's once between every frame.
ScrollCreditsMonLeft_SetSCX is not updating the hram value at all. So if you enter Vblank while waiting in the loop, whatever information rSCX had is getting overwritten by the outdated position in hSCX. This results in the strange scrolling artifact you showed. They are stray frames with the wrong scroll value. The solution is to keep hSCX updated with each loop as below.
ScrollCreditsMonLeft_SetSCX:
ld a, h
ld [hSCX], a
ld a, [rLY]
cp l
jr nz, ScrollCreditsMonLeft_SetSCX
ld a, h
ld [rSCX], a
.loop
ld a, [rLY]
cp h
jr z, .loop
ret
For some reason, this bug only shows up on the GBC and GBA when running a game in color-mode. I can only speculate as to why the DMG, Poscket, and SGB are unaffected. Retail Red and Blue never showed the issue on a GBC because they run in monochrome-mode, and Yellow doesn't show the issue because the way the credits were handled was rewritten.