Jeff Harris

Software engineer, hobbyist game developer

Slack client for Commodore 64

Slack is great. Many smarter people than me also think that Slack is great. Slack is great because its simple and easier to deal with than emails. With all the time it saves me on emails, I   relax   go the beach   write more code   send messages via Slack instead.

But while Slack might be great, it does not have a great native client for the Commodore 64. In fact, they have no client for Commodore 64 at all!

This is clearly a problem.

Reasoning that “a pull request is better than a complaint”, I’m happy to present the first (and most likely only) Slack client for Commodore 64!

“Team communication for the 21st century” … now backwards compatible with 1985!

The C64 has an extension port called the Userport which, via an adapter, can communicate over RS-232 serial. I connected the Userport to a Raspberry Pi with a artisanal, locally sourced, homemade cable with the UserPort connector on one end, and a usb TTL-RS-232 converter on the other. The fastest I have been able to run this reliably is a solid 1200 baud / 150 bytes per second.

On the Commodore, I wrote an application in 6502 assembly. It uses built-in Kernal ROM functions to read and write the serial port and update the screen.

On the Pi, I wrote a NodeJS app which talks to the Slack RTM API. It is reponsible for translating a simple RPC protocol between the C64 and itself and connecting to the outside world (in this case, Slack). It uses serialport to talk to the USB serial driver.


A simple RPC message format is defined between the C64 and Pi. The description below is all C-style, but of course on the C64 this is all implemented in 6502 assembly.

struct rpc_message_t {
  char command_id;
  void *payload;
  char message_end_marker (0x7e);

struct channel_t {
  char len;
  char[9] channel_id;
  char[len-9] channel_name;

When the Pi gets a connection to Slack’s RTM api, it kicks off communication with the C64. The protocol follows like this:

[Pi >> ] HELLO {user: jeff}
[Pi >> ] CHANNELS_HEADER { channel_count, list_size_in_bytes }
[Pi >> ] CHANNELS_LIST { channel_data }

// user selects a channel on the C64
[Commodore >> ] CHANNEL_SELECT { channel_id }

// message arrives via Slack RTM api in the selected channel
[Pi >> ] MESSAGE_HEADER_LINE { ascii_data }
[Pi >> ] MESSAGE_LINE { ascii_data }
[Pi >> ] MESSAGE_LINE { ascii_data }

// user sends message from C64
[Commodore >> ] SEND_MESSAGE { message }

When the channel data has finished streaming, we switch to the Channels screen. This shows a scrollable list of all channels and groups, ordered by unread_count, name. Hitting [RETURN] on a channel name sends channel_id to the Pi and switches to the Messages screen.

When a channel is joined, the Pi app sends the last couple of messages in the channel to the C64. Subsequently, whenever a message for that channel is recieved via the Slack websocket connection, it gets converted into a multiple lines of C64-compatible characters and sent across the serial connection.

Slash commands work too! We use the undocumented chat.command API found with help from Chrome dev tools :)

Heres an example of the kind of code running on the C64. This is the top level processing loop:

Want to do this yourself? Of course you do. Why else are you still reading?

Hardware needed:

  • 1 x Commodore64
  • 1 x Raspberry Pi (really anything with usb which can run NodeJS)
  • 1 x homemade C64 Userport <-> USB serial cable. instructions


It goes without saying (surely?!) that the company named ‘Slack’ is not affiliated in any way with this project. I’m not sure if they would be happy or horrified to see this creation.

Rendering GISHWHES logo on Commodore64

I’ve had a flood of emails and tweets about how to render the GISHWHES logo on the C64. I’d never heard of it, but it sounds like a pretty cool treasure hunt held for a week once a year.

And one of the items to create/find is rendering the GISHWHES logo on a C64/TRS-80/Apple-II. I don’t know about the last two machines, but since I worked on exactly this for the C64, I’ve somehow become the goto person for this!

To make it completely fair, I’m just going to post some more detailed steps for how to accomplish the above goal.

Convert gif into a double-sized C64 hardware sprite:

git clone
cd gif-to-c64-sprites
npm install
node gif-to-sprite.js --doubleSize /path/to/gishwhes_logo.gif

Create and run C64 app:

Edit c64-sample-app/gif_sprite.asm, change .FRAME_COUNT=20 to .FRAME_COUNT=<number of frames in your gif file>
Edit c64-sample-app/main.asm, line 9, replace 'output.spr' with the path to your generated sprite (../output.spr)

Use ACME cross assembler to assemble the .asm files into a .prg file. This file should now be runnable on a C64 emulator.

To get the app onto real hardware is more complex, you’ll either need to have a sdcard-backed disk emulator (like this) or write a real floppy disk. Or, rewrite this code in BASIC and type it out! So many options! :)

Rendering animated GIFs on a Commodore64

If you’ve always thought the one thing the world needed was rendering animated GIFs on a Commodore64, then you’ve come to the right place! I’ve written a tool called gif-to-c64-sprites which takes an animated GIF file as input, and outputs a stream of Commodore64 hardware sprite format data.

TLDR; show me the final result

How does that work?

First, a refresher on C64 hardware sprites… Hardware sprites are 24x21 pixels in size, and can be moved freely around the screen, either above or below the character or pixel-based screen memory. They are commonly used for small moving items because they do not require memory to be copied around to change their position on the screen. The VIC-II graphics hardware is responsible for rendering the sprites, freeing the CPU to do other things. Up to 8 sprites can be displayed at once, each one enabled by setting the corresponding bit in $d015 ( sprite-enable register). Other registers specify the pointer to sprite data, position of the sprite on the screen and color, horizontal and vertical scaling, and collision detection with another sprite.

This example image shows how the data for a default single-color sprite is laid out. A sprite only takes up 63 bytes. In single-color mode, those 63 bytes are used to represent 24x21 pixels, where the pixel can be either set or not set and is represented with a single bit.

24 bits (3 bytes) across * 21 rows = 63 bytes. In the image, the first row is the byte count, the second row is the bit count.

The sprite data pointer register (like all registers) is only 8 bits, but the sprite data can live anywhere in the active 16kb memory bank - how can that work!? To make the whole 16kb addressable, the value in the register is multiplied by 64 internally by the VIC-II before fetching from memory. In effect, the register selects which of the possible 256 locations to read sprite data from, rather than the raw memory address. The constraint this implies is that we must place sprite data on a 64 byte boundary. Heres some example code to enable sprite #0:

To animate a C64 sprite, first you need to store multiple 63-byte chunks of sprite data, one after the other, on 64-byte boundaries. (eg at 64, 128, 192…). Then on each screen refresh you change the data pointer to point to the next chunk of sprite data, by doing inc $07f8 or similar. This command adds 1 to the specified memory address. Because the value of the register is multiplied internally by 64, this has the effect of moving the pointer to the start of the next 64 byte chunk of sprite data. Once you reach the last chunk of sprite data, you reset the pointer back to the initial value, and you have an animation loop!

Thats the C64 side of things, for more details, there are plenty of better descriptions than mine!


Now that we know how to animate hardware sprites on the C64 the only trick left is how to generate the sprite data. SpritePad is a great tool but unfortunately I am too lazy to create my own assets. :(

Instead I wrote gif-to-c64-sprites - a little node script which uses gifsicle and get-pixels to pick out pixel data from each frame in an animated gif. Each frame is converted into a C64 sprite chunk by bitshifting pixels into byte buffers. As it only currently outputs single-color sprites, it works best for cartoon-like source images.

Below are some examples I generated using the tool and the C64 sprite animation code above.

Double-size mode

When you use the --doubleSize option, 4 sprites are generated per frame, by splitting the source image into 4 quadrants. This gives better image quality, with the expense of using 4x the amount of data. On the C64 we display 4 sprites in a square shape next to each other to create the image. In the screenshot below, I’ve set each sprite to be a different color to illustrate how the final image is combined. There is an example C64 app showing how to do this in the gif-to-c64-sprites repo.

Conversation on reddit -

Rendering animated GIFs on a Commodore64 from gamedev