// 2025-11-30 // by Elder0010

Commodore 64 demo released in 2025 as a Genesis Project / Extend coop production. Reached #01 at the 2025 edition of Transmission64 demo competition.
Release date: 30/11/2025
Credits:
This demo required 2 years of work - it marks a huge milestone in my “old computers” journey. This is the result of a team of 3 scattered around Europe: me (Elder0010), Psych858o and Sulevi. A co-op production, created “by hand”, instruction by instruction, pixel by pixel, note by note. After witnessing the majority of the people I know surrender to the AI because “it’s how it’s done today / i can get results without efforts / you’ll end up using it as everyone else / i can write code even if i don’t know how to program” and things like that I decided to use the most powerful weapon against it - a demo for the Commodore 64.
To all the artists and hackers (aka code or system engineering artists) sharing this line of thought: everytime you fight against it, raise people’s awareness about it, use the human made made logo to mark your creations or simply refuse to use it, you’re giving fuel, power, blood and caffeine to my passion and will to continue this battle.
I am grateful, and this demo is for you, from the depths of my heart. We Are The Anomaly.
This demo features a huge work on the synchronization between the events on screen and the music.
A big shootout goes to Sparta for the effort he put in his Sparkle loader system. I have been using it extensively in this demo, and I tested everything on real hw (so real c64 + real 1541) under extreme conditions to say the least.
Every scene requires a strict (frame perfect) loading time and I was scared that the :“real” disk drive couldn’t handle this, due to the unovaidable speed wobble of the mechanism.
Here are some test results i wanted to share:
The 1541U ultimate cartridge can lead to false results when testing demos against the drive speed - it’s faster than a real disk drive, even tho i didn’t measured the “distance”. Perhaps a speed setting should be provided to simulate various “real life” loading situations.
Any 1541 / 1541-II disk drive will have a (very small) speed wobble that could eventually cause issues, but there’s a huge gap between loading and writing. What I mean is that a 300 +-3 rpms (perfect speed) 1541 (or 1541-II) will 100% work in reading (easiest case) and formatting (hardest case), while a 270 RPM drive will probably load a small file from the kernal loader, but it will not write or format.
In conclusion: I did a huge amount of stress testing and Sparkle handled everything for me without any extra work. Believe me, the loading times of the demo are -strict- to say the least. 2/3 frames of delay and bam: music sync is gone.
As a bonus, once you deal with the PITA of testing with different / real drives, you can take the 1541-II ultimate for granted (that is, what 99.99% of the people with a real c64 will use for your production..)
Codewise, the 2 technical highlights of this demo are the “Arcade Scroller” and the “Stretcher” parts.
This routine has been inspired by the game Street Fighter II. The idea is to have a smooth horizontal scrolling of a large map (936x96 pixels) with 96 different layers of parallax, to simulate a perspective effect. You can find the original idea implemented on the floor of the Ryu stage (for example).
Of course the C64 has no hardware support for smooth scrolling of large maps with parallax layers. Therefore, everything has been implemented in software, using cycle exact raster interrupts and some clever tricks. I have “counter skewed” the original image, so that each line of the floor will compensate the actual horizontal scrolling speed for each line and prevent a ugly warping on the texture. Each line has a different scrolling speed threshold that is compared against a frame counter. When the scrolling speed counter of a line reaches its specific threshold, that line is shifted by one pixel. This way, the lines at the bottom of the screen (closer to the viewer) will scroll faster than the ones at the top (far from the viewer), simulating a perspective effect.
But there’s more! Moving pixels in memory is slow on the C64, especially if you want to move a lot of data. Therefore I took advantage of the soft scroll register ($d016) which gives a 0-7 pixel offset at no CPU cost. Every 8 pixel, the whole line is shifted in memory by one byte, and the soft scroll register is reset to 0. This way, I can move line-by-line in a independent fashion the whole floor map with a combination of soft scroll and memory shifts, reducing the CPU load. This $d016 soft scroll handling is done in a raster interrupt, and the value of the register is of course updated 96 times at each frame (one per line of the floor).
Also, since each line has a different scrolling speed, I had to find a way to avoid a huge amount of “worst cases” for the lines - that is when a line needs to be shifted in memory after the soft scroll reaches 7. To solve this, I scattered the lines in a somewhat random 0-7 offset pattern. This has been a matter of trial and error, until I found a distribution that minimized the worst cases.
Having solved the scrolling issues for the bottom part of the screen, I had to deal with the upper part of the screen, which also scrolls horizontally (without any perspective) at the same time of the floor. This has been achieved by using a double buffer for the screen memory. While one buffer is being displayed, the other is being updated with the new data for the next frame.
What I did is checking whenever we are in a “good” case of scrolling for the floor (that is, not too many memory shifts for the floor are needed and music is not using too much cpu), and use a part of the cpu available in that frame to update a section of the upper part of the screen in the next video buffer. The check is very simple: if, after updating the floor lines there’s still enough CPU time left before the next frame (measured in rasterlines), then it’s a good case. The upper part of the screen is divided in several sections (each “row” is 8x40 bytes for the pixels + 40 bytes for the colours), and each good case frame is used to update one section of the upper part of the screen in the “new” buffer.
While updating the “wall” buffer, we can however have continous movement of the upper part of the screen, again using the soft scroll register slowly enough to let the preparation of the new buffer happen in time and still have a continous scrolling effect.
When the upper part of the screen is fully updated and the soft scroll register reaches 7 again, the buffers are swapped so the “new” one is displayed on screen.
The whole routine is highly optimized (at least for my skill level), and the icing on the cake has been the usage of the illegal 6502 opcode DCP to achieve the best performance. The map data is stored in a uncompressed line-by-line format and scrolled on the fly while the music is playing and the upper part of the screen is scrolling as well, with also some sprites action on the topmost layer of the screen.
The final result is a smooth scrolling screen with 96 parallax layers, running at a solid 50fps on the C64! This is not the first time a similar effect has been achieved on the C64 - the legendary Coma Light 13 demo featured it already, but I am proud to have implemented my take on this technique from scratch and acquire a lot of knowledge (and patience) in the process. Also, my version has a larger map, suffers way less from the unaivoidable “horizontal warp distortion” of the texture and it’s also scrolling the upper part of the screen, which is a nice improvement to the Coma Light one.
This routine focuses on a multilayered screen featuring a distorted texture continously scrolled vertically. Basically the screen is organized in 4 different layers, listed here in order of priority.
BG0 is the plain Commodore 64 background colour. You can’t have any graphics here - only horizontal lines. Considering an 8X8 pixel block, BG1, FG0 and FG1 are the 3 colours available for the multicolour bitmap image - the “HUD”. Then there are the sprites, which are on top of BG0 / BG1 but below FG0 / FG1.
This is done without any hardware trick, because the C64 has a built-in priority mechanism for the sprites. With the $d01b register you can have them in the absolute top layer (but below the border), or below the foreground layers. But, here’s the catch. Having the sprites in low priority mode while using the multicolour bitmap mode will put them on top of any pixel using the %01 nibble for colour selection anyway. I have used this to have the sprites on top of BG0 and BG1, but below FG0 and FG1.
Problem is, that the 8 C64 sprites are can cover an area of maximum 24*8 = 192 pixels horizontally and 21 pixels vertically. Not enough to cover the a big part of the screen with a scrolling texture.
There are several approach to solve this problem, but the one I have used is sprite stretching. Each sprite can be stretched vertically by a factor of 2 using the $d017 register. By altering the stretch register at each line using a raster routine, it’s possible to have each sprite stretched or not on a line-by-line basis, thus to repeat the lines and arbitrary stretch them to cover a larger area of the screen. The stretched - unstretched lines of the texture are altered at each frame, to create a very subtle vertical waving distortion effect.
The texture used is kinda big: 192x1112 pixels, even tho only 21 lines (heavily stretched on Y) are visible at a time.
But again, timing is critical. Each 8th line of the screen, the VIC takes control of the bus for 40 cycles, so there’s not enough CPU time update the stretch register at the correct moment. The solution I have found is to continuosly delay the occurring badlines by changing the vertical scroll bits of the $d011 register, but this comes at the cost of a severe colour constraint:
Since the the badlines are continously delayed as soon as the stretching effect starts, the VIC-II will “remember” the colours of the previous 8x8 block fetched before the stretching started. Therefore, the colours of the HUD (BG1, FG0, FG1) must be the same for each 8x160 block of the area covered by the stretching effect. To keep the design coherent, Sulevi created the colour scheme of the HUD with this constraint in mind, using columns of 8x200 colour constrained blocks. Pixels of the bitmap are unaffected by this - they are fetched normally by the VIC-II in any case.
To summarize, the Stretcher scene is a combination of: - Standard multicolour bitmap mode - Sprites in low priority mode to have them below FG0 / FG1 and above BG0 / BG1 - Sprite stretching on a line-by-line basis using $d017 - Badline delay by changing the vertical scroll bits of $d011 on a line-by-line basis - BG0 lines by changing the background colour register $d021 on a line-by-line basis - Extra horizontal shift (the “sinewave” effect) using the $d016 soft scroll register on a line-by-line basis - A continous scrolling of a 192x21 pixels buffer taken from a large 192x1112 pixels texture - A continuous vertical waving distortion of the texture by altering the lines being stretched / not stretched at each frame - A clever colour scheme for the HUD designed by Sulevi following the routine constraints - Some extra juice with the horizontal sinewave distortion using the $d016 soft scroll register on a line-by-line basis