http://1amstudios.com/2014/12/07/c64-smooth-scrolling/
https://www.c64-wiki.com/wiki/Scrolling
* The top 4 bits of $D018 (VM10-VM13) control the base of graphics memory
* The bottom 3 bits of $D011 (YSCROLL) and $D016 (XSCROLL) let you delay screen display by 0-7 pixels in either axis
* The 4th bit of $D011 (RSEL) and $D016 (CSEL) let you shrink the screen viewport so it's visibly 304x192 pixels (in NTSC) even though the screen memory is still 320x200.
VM10-13 lets you establish a double-buffer, you can switch instantly between a front and back buffer by changing $D018. While you are scrolling, you copy the front buffer to the back buffer, offset by 8 horizontal pixels (1 byte) or 4 vertical pixels, then add in new map data on the edge you're scrolling towards. On each frame, you update XSCROLL/YSCROLL by one pixel so the visible screen is moving towards your new screen, then once it's moved all 8/4 pixels, switch to the new buffer.
The cost of copying all that graphics memory is expensive, so split it across the 8/4 frames.
But a few years later, the Amiga brought us DPaint and Blitz Basic, and suddenly it was very possible to make a pretty competent game in BASIC as a self-taught teenager with no Internet access. That’s probably a better choice for anyone wanting to experiment with retro game dev using the tools of the period without resorting to assembly language
Assembly becomes really attractive really quickly.
In general, this is a routine that is super easy to write in 6502 assembly. Most magazine BASIC games had something like that, with a few such routines that were POKEd in memory at startup. Several were written in a relocatable fashion so that they could be copied easily from one game to the next.