TABLE OF CONTENTS
- INTRODUCTION
- THE X16FONTS MAIN SCREEN
- UTILITY FUNCTIONS
- OPTIONS FOR SAVING YOUR FONT
- TYPICAL USAGE
- X16FONTS SAMPLES (and how to load X16FONTS)
How to Get X16 Fonts: X16FONTS is on the X16 SD card under \APPS\X16FONTS
it is also available here https://github.com/voidstar78/X16FONTS
INTRODUCTION
While original Commodore PETSCII has a certain charm, one of the first things I wanted to do with my Commander X16 was make use of custom fonts.
It wasn’t quite clear initially on how to do that. So, I tried writing my own Font Editor in BASLOAD, and X16FONTS.BASL is a result of that. I’m still not exactly sure how I figured it out – but it was a combination of slogging through the X16 Technical Reference (here) and trial and error.
First thing to know is, the “font address” doesn’t appear in the (System) Memory Map. The “standard” System Fonts (and there are multiple of them) are retained in the System ROM exclusively in Bank 6. As part of the system startup, it copies that ROM data over into VRAM.
Where in VRAM? Go to the X16 VERA Programming Reference, and search for “charset.” Instead of “font” the terminology here is “charset.” You will see it says $1:$F000 and goes for 2KB (exactly 2048 bytes). There are 256 separate font entries available, so 2048 / 256 = 8 bytes per font. Each font is represented by a “byte-mask” of 8 rows (where a byte is 8-bits). But how do you access VRAM? I’ll skip on how to do so from assembly for now – first, just know that the BASIC keyword VPOKE and VPEEK were added just for that purpose of accessing Video RAM.
So, try this as an experiment: the first font symbol is (by default) the ‘@’ symbol. Note that fonts go by “display code” index (which is not necessarily the same as keyboard scan code orders). So just type ‘@’ and press RETURN. It’s a command that essentially doesn’t do anything, but we just want a ‘@’ on the screen. Then type VPOKE 1,$F000,0 and see what happens to the ‘@’ symbol.

You’ll notice that the first row of the ‘@’ symbol is now gone, because that portion of the resident VRAM font was set to 0. You can try other values besides 0, like VPOKE 1,$F000,$FF or VPOKE 1,$F000,170 ($FF = 255, 170 = $AA = 10101010 in binary). To restore the default system font, just press SHIFT+ALT to cycle through the main system fonts. You can also do A=VPEEK(1,$F000):?A to see the current byte-mask value. You can do PRINT HEX$(A) or PRINT BIN$(A) if the hex or binary view is more helpful to you.

So now with knowing just that, I was ready to begin writing X16FONTS!
THE X16FONTS MAIN SCREEN
The X16FONTS main screen is divided into four main areas:

- Top Left: this is what the font will look like when used. The current specific font being edited is the intersection between the two green arrows (and is also highlighted in “inverse”). This selection is chosen by using the “WASD” keys. The number at the top of this section (to the right of “DISPLAY CODES”) is the offset of the currently selected font (in decimal, so it has a range of 0 to 255). This is helpful for know which index to use when using the TILE keyword in the Commander X16 BASIC. Next to this number is “N=” where the N there corresponds to the current row number in the main font editor (this helps when using the V and L commands to know which N is being SAVED/LOADED), if you just want to work with a single row of modified fonts rather than the entire set.
- Top Right: “editor box” of the currently selected font, expanded into the eight rows of eight bits. The exact bit that will be edited is the intersection of the two green arrows. The selection is adjusted by using the arrow keys. To the left of each row if the hex address of this corresponding font (in VRAM). As you select a specific bit, use SPACEBAR to toggle the bit. You will see the effect appear immediately at the top left. You can clear the entire selected font using C, or E to set all the bits. You can invert bits by pressing I (doing so will pop-up a little menu, where you can press C for current column, R for current row, or B for both the current col and row, or press ESC to cancel).
- Bottom Left: This table on the bottom left corner is to help know which font will appear when using PRINT CHR$(x) from Commander X16 BASIC (which will be slower than TILE, but maybe just more practical to you). BASIC uses a different arrangement than the display codes. This arrangement can be thought of being split into two halves – indexes 0 to 127, and 128 to 255. The first 32 characters of both halves is reserved as “special control codes” for either adjusting colors, moving the cursor, or other effects. This is why they appear as “gray” in this chart (because they won’t print as-is; in order to print these, you have to first prefix them with a PRINT CHR$($80) to specify to BASIC to print the next character as uninterpreted). There was not room to show all these characters at once, so you can press “[” or “]” to cycle between the two halves. So, to print the heart symbol, you would do PRINT CHR$($D3) (where $D is the row, then offset $03 for the column). Note that $D3 hex is 211, so PRINT CHR$(211) is also acceptable (and slightly faster since you are doing the hex conversion manually for BASIC).
- Bottom Right: This area is just a reminder about the keyboard inputs to do various operations. Luckily there is just enough space to show them all, so no need for a more elaborate F1 help.
UTILITY FUNCTIONS
- If you want to “simulate” how the font looks with different background colors, use the “B” key to cycle through those background colors. Note that it currently only cycles between black and blue. You’ll have to modify the BASLOAD code if there are other colors you prefer (search CYCLEBACKG).
- You can copy existing font entries to different indexes. This is useful if you want a kind of “animation” where the next font is slight variation of a prior font (that would be shown in a cycle sequence). Or if you just want to borrow most of an existing font. A copy is done using the K command, which will prompt you on which index you want to copy. So first go to the font index you want to copy, and note down the number at the top. Then go to the font index where you want to copy that font into, press K, and enter in the noted number (or press ESC to abort).
- If you found that you’re just “off by one” in your font, and you just need to rotate the pixels by one column or row, you can use the YGHJ keys. Y and H will rotate by one row up and down (automatically rolling over at the edges), and G and J will rotate one column left and row (also rolling over at the edges). So an easy way to make an animation is to take the first font, then copy it over to the next index, then just rotate one pixel it as desired.
- If you want to revert to the original standard Commander X16 font, you can press SHIFT+ALT. X16FONT focuses on modifying the “currently active” font, but there are several fonts stored in the System ROM. SHIFT+ALT is a standard System ROM feature to cycle between the two main PETSCII fonts back into VRAM (as is done during normal startup of the system).
OPTIONS FOR SAVING YOUR FONT
There are three ways to save your font, and the choice will depend on how you want to handle loading your modified font.
- Option 1: The first way is to use the V and L keys. At the top is “N=xx” where xx is the current row in the font selector. V will only save the current row you are on. For example, if you are row 1, then the data will be written to “X16FONT 1.DAT” . The decimal value of each row of font bytes is written in order, so each file will have 128 decimal values (16 fonts * 8 rows each). When you modify a row, X16FONTS will show an asterisks (*) to the left side of that row – this is a reminder that this row has been modified and has not yet been saved using V. Similarly, for the current row, you press L to load the corresponding X16FONTxx.DAT file for that row. You can borrow that read code from the X16FONT BASLOAD BASL source, but there is a better way (see next options).
- Option 2: Pressing X will export the current row to a file called “FONT xx.BAS” where xx is the current row. This is similar to the above Option 1, except you will notice it takes longer. The reason it takes longer is because it is exporting the exact BASIC code you would need to initialize that font. This is useful if you don’t want to have an extra “font file” to pass around with your program. But running that code will take a noticeable amount of time (and use a lot of code space), so it is divided into separate files in case you just want to “surgically” only apply a few modified rows in the font. FONT 1.BAS starts as line number 30,000 which should isolate it from any of your own code, so you can just insert it straight into your BAS text file. And the output takes a while because of the string processing (in BASIC) to export this code using the “%” binary sequence supported by BASIC (so you can then visualize the font right in your code). X16FONTS can re-load fonts back in from this same format, so this option is just for helping to export out in support of other BASIC programs.
- Option 3: This last option saves all the fonts (of all rows) into a single FONTALL.DAT file. This option is the fastest and probably what most people will end up using. The format used here is different than the DAT files used in Option 1. The format used in this option is compatible with the Commander X16 BASIC BVLOAD command. That is, it is a “literal” binary copy of what is VRAM. And BVLOAD is incredibly fast, such that the entire set of fonts (256 of them) is loaded nearly instantly (so fast, it may be possible to animate something across multiple font files). The full command will look like this: BVLOAD “FONTALL.DAT”,8,1,$F000 (8 is the device number, so using 8 does assume the SD-card; the 1 is the VRAM portion to use).
Note that after each file operation, on the left side you will see “ST=xx” appear. This displays the last file system status reported by the file operation (save or load). A “normal” status value is 0, which indicate no error. If there is a problem with the current SD card or file system, then a non-zero value will be displayed.
TYPICAL USAGE
What I do is I keep multiple instances of the X16 emulator running – one for the application I’m developing, then another instance running the X16FONTS program (which I just copy over into the working folder of whatever other application I’m developing). Typically I’ll start with the PETSCII upper/lower font, and then just clear out the later-half (index 128 to 255). Do this by just using WASD to move across them and press C. The later-half is just the inverse of the first half (by default).
After modifying the font for a little while, be sure to use V to save modified rows, or Z to export all the font into a single DAT file. There is no auto-save and you don’t want to lose your work, so just using Z every few minutes is a good idea. If working across a few days, you may want to archive your folder also every once in a while. Inevitably, you may inadvertently do a LOAD instead of a SAVE, thus another way to accidentally lose work (because there is no luxury of an “are you sure?” prompt here).
Then in your development instance, use your preferred approach to loading the font (as described in the prior section). I typically just use the BVLOAD since it is very fast. If you use one of the auto-generated BAS files (to avoid having to pass around another file with your program): remember to add a line in your code to GOSUB to this font initialization (and add a RETURN at the end, since that part isn’t generated for you – since it is unknown how many auto-generated rows you want to use).
As another usage tip: if you press ESCAPE and exit X16FONTS, you won’t lose your fonts right away. They are still resident in VRAM. So if you just “RUN” again (right away), the same font will appear in the editor. This is done so you can press ESCAPE and then exercise a TILE or PRINT CHR$ command to “test” your font. But if you press SHIFT+ALT or load and run some other program, then VRAM will be overwritten. So don’t panic if you accidentally ESCAPE out of X16FONTS, just issue RUN again to get right back where you were.
X16FONTS SAMPLES (and how to load X16FONTS)
If you want to see some starter examples, in the APPS/X16FONTS folder are two examples (fully exported, so those folder both have a lot of files in them). Here is an example of how you would get to the first sample:

After running from the SAMPLE1 folder, then use the Q command to import the FONTALL.DAT and the example should look like this:

Note that you can “compile” the X16FONTS.BASL file also. Do command BASLOAD “X16FONTS.BASL” then RUN.
CONTROL CODES
An overview of ISO mode and Control Codes is in the X16 Reference “Editor” section (here). There is a table there that explains the two sets of 32-character control codes. You can do things like block users from changing character sets (more “professional” application will do this, so users don’t accidentally “crush” your custom font by pressing SHIFT+ALT), change current terminal color, swap FG/BG colors, or some of the ancient ASCII things (like 7 for bell, 10 for linefeed, 13 for carriage return).
Note that you can press CTRL+O (this is to enter ISO mode) and startup X16FONTS to start with the ISO set as the default starting reference. But to exit ISO mode, you have to ESCAPE and do PRINT CHR$($8F) (in upper case).
As mentioned, if you want to print the symbol associated with a control code (instead of invoking that control code), you have to prefix the console output with $80. For example:
PRINT CHR$($80);CHR$($07)
The above will print the font symbol associated with index 7, instead of the normal behavior of invoking a beep audible sound.
OTHER QUESTIONS
Can find me at the X16 Forum or Discord if you have any questions!