My game is vector graphics from end to end: asteroids as polylines, ship as line segments, shots as pixels, white strokes on black throughout. A pixel font from the TEXT command sat in there like a sticker on a vector painting, and it didn’t scale freely either. So I built my own typeface, also drawn as line segments, so it matches the rest of the screen.

Type as line segments

Each character is a set of line segments on a 5×7 grid. At draw time the coordinates get multiplied by a scale factor and shifted to the anchor position. Scaling is essentially free.

I store the data in DATA statements, one entry per character with the ASCII code, the line count, and the x1,y1,x2,y2 coordinates:

font_data:
DATA 32, 0 ' Space
DATA 65, 4, 0,7,0,0, 0,0,5,0, 5,0,5,7, 0,3,5,3 ' A
DATA 66, 7, 0,0,0,7, 0,0,4,0, 4,0,5,1, 5,1,4,3, 4,3,0,3, 4,3,5,5, 5,5,0,7 ' B
DATA 79, 4, 0,0,5,0, 5,0,5,7, 5,7,0,7, 0,7,0,0 ' O
DATA 48, 4, 0,0,5,0, 5,0,5,7, 5,7,0,7, 0,7,0,0 ' 0
DATA -1

At startup I read it into two arrays, ASCII code as the index:

DIM INTEGER font_lines(127)
DIM FLOAT font_coords(127, 19, 3)

SUB InitVectorFont()
  LOCAL INTEGER c, nl, i

  RESTORE font_data
  DO WHILE 1
    READ c
    IF c = -1 THEN EXIT DO
    READ nl
    font_lines(c) = nl
    FOR i = 0 TO nl - 1
      READ font_coords(c, i, 0), font_coords(c, i, 1), font_coords(c, i, 2), font_coords(c, i, 3)
    NEXT i
  LOOP
END SUB

Drawing a character

Pull the lines out, scale by size, offset by the anchor, done:

SUB DrawVectorChar(char$, x, y, size, col)
  LOCAL INTEGER ascii_val, i, num_lines
  LOCAL FLOAT x1, y1, x2, y2

  ascii_val = ASC(char$)
  IF ascii_val < 0 OR ascii_val > 127 THEN EXIT SUB

  num_lines = font_lines(ascii_val)
  IF num_lines = 0 THEN EXIT SUB

  FOR i = 0 TO num_lines - 1
    x1 = x + font_coords(ascii_val, i, 0) * size
    y1 = y + font_coords(ascii_val, i, 1) * size
    x2 = x + font_coords(ascii_val, i, 2) * size
    y2 = y + font_coords(ascii_val, i, 3) * size
    LINE x1, y1, x2, y2, 1, col
  NEXT i
END SUB

A string routine on top draws each character and leaves space between them:

SUB DrawVectorText(text$, x, y, size, col)
  LOCAL INTEGER i
  LOCAL FLOAT current_x

  current_x = x
  FOR i = 1 TO LEN(text$)
    DrawVectorChar(MID$(text$, i, 1), current_x, y, size, col)
    current_x = current_x + 5 * size + 2 * size
  NEXT i
END SUB

With size = 1 the type is 7 pixels tall, size = 3 gets you 21 pixels, size = 5 is huge. All from a single source.

What stuck with me: DATA/READ/RESTORE in MMBasic is a real lookup-table tool, not a relic. The ASCII-indexed array replaces every IF-chain with a single read. And the scalability, the actual reason for the whole exercise, is free — multiply by size, done. The initial setup took maybe an hour, and after that I had a typeface sharing the visual language of the rest of the game and looking identical everywhere on screen.