EN /HU | Login

Pixelia BBS

The art board of the BBS network: classic ANSI art from the 16colo.rs archive, a shared 40×25 canvas that every caller paints on at the same time, and the Wall of the works saved from it.

Live at teletypegames.org:2332, in the browser on bbsweb, and through TTG Gate BBS

Overview

A Ruby app on the rubbs gem, like the Teletype BBS, Scriptorium BBS and Commodex BBS.

It has two faces on one port:

  • Modern: ANSI colours, windows, menus and the mouse (SyncTERM, NetRunner, PuTTY, bbsweb). A piece of art on the whole screen, the canvas in a window with a clickable palette.
  • Commodore 64: PETSCII on a 40×25 screen, for a C64 terminal program (CCGMS, Novaterm, UltimateTerm) behind a WiFi modem. The canvas is the C64 screen itself, and an ANSI piece is shown 40 columns at a time.

A call starts with rubbs' BBS::Terminal question: RETURN takes the guess, 1 picks the modern face, 2 the C64.

The gallery

16colo.rs. The board browses the 16colo.rs archive through its public API: a year, a pack, a file. It lists the text-art files (.ans, .asc, .diz, .nfo, .txt, .ice, and any file whose SAUCE says ASCII, ANSI or ANSiMation) with their title, artist, group and 16colo.rs address. Nothing is mirrored: a file is fetched when someone opens it (at most 512 KB) and kept in a 100 MB disk cache; the listings stay an hour in memory.

The board renders the art itself: it reads the SAUCE record, CP437, the ANSI.SYS escapes and iCE colours, wraps at the SAUCE width, and stops at 1000 rows. On a modern terminal the piece scrolls on the whole screen. On a C64 it comes in pages of 40 columns: the CGA colours go to the nearest C64 colour, a coloured background becomes reversed video, and R or CRSR right steps across a wider piece.

The Wall holds the works saved from the canvas, newest first, with title, handle and date, drawn natively on both faces.

The canvas

One shared 40×25 canvas, the size of the C64 screen, so both faces show it cell for cell. Everyone on it sees the others' strokes within a few seconds. A cell holds one character in one of the 16 C64 colours, as ink on black or reversed; that is what a C64 cell can show, so the picture looks the same everywhere. The characters are the ones both a Unicode terminal and PETSCII have: letters, digits, most signs, box lines, blocks and the half blocks.

On a modern terminal:

Key Action
F3 Open the canvas
Arrows, typing Move, paint the character
F7, F8 Previous / next ink (or click a swatch)
F9 or Ctrl-R Reverse on and off
Insert or Ctrl-G Glyph mode: letters paint the brush glyphs
Mouse A click places the cursor, a drag or a right click paints
Ctrl-Z or Ctrl-U Undo your own last cells
Ctrl-S Save to the Wall (Alt-S in the form)
F2 16colo.rs by year
F4 The Wall
Alt-X Log off

On a Commodore 64: CRSR moves, typing paints, DEL rubs out, F3/F4 change the ink, F5 turns reverse on and off, F6 switches glyph mode (the letters are laid out like the keyboard: Q W E / A S D / Z X C are the box corners, tees and the cross, G is a full block, T and B the top and bottom halves). RETURN, RUN/STOP or ← opens the command row: ink, reverse, glyphs, save, help, quit. F1 and F7 are left alone, UltimateTerm keeps them. The board sends only the cells that changed, a couple of bytes each, so the canvas stays quick at 1200 baud.

Limits: 20 cells a second per call, one Wall save every five minutes per call, a title of 32 and a handle of 16 characters.

Configuration and data

Variable Default
PIXELIA_BBS_DATA data the canvas, the Wall, the cache
PIXELIA_BBS_API_URL https://api.16colo.rs the 16colo.rs API
PIXELIA_BBS_SITE_URL https://16colo.rs the files and the links shown
PIXELIA_BBS_USER_AGENT PixeliaBBS/1.0 (+https://teletypegames.org; …) sent to 16colo.rs
PIXELIA_BBS_API_TTL 3600 seconds a listing is kept
PIXELIA_BBS_MAX_FILE_KB 512 the largest art file fetched
PIXELIA_BBS_CACHE_MB 100 the art cache's size
PIXELIA_BBS_MAX_ROWS 1000 rows rendered of a piece
PIXELIA_BBS_PAINT_RATE 20 cells a second per call
PIXELIA_BBS_WALL_COOLDOWN 300 seconds between two saves of a call

The canvas is data/canvas.json (written every two seconds), the Wall one JSON file a work in data/works/. The admins moderate on the server:

SH
docker exec pixelia-bbs bin/works list           # the Wall
docker exec pixelia-bbs bin/works show ID
docker exec pixelia-bbs bin/works remove ID
docker exec pixelia-bbs bin/canvas clear         # archives the canvas to data/archive/, then blanks it

The board has no secrets.

Under the hood

A push to master deploys it from Woodpecker (RuboCop, compose check, ci-deploy pixelia-bbs); the container is pixelia-bbs, in /srv/stacks/pixelia-bbs, and data/ stays between deploys. The entrypoint updates rubbs on start.

The code follows the house layering: lib/domain (the colour, glyph, canvas, work, SAUCE and art models; the 16colo.rs, art-cache, canvas and work repositories; AnsiRenderService, GalleryService, CanvasService, WallService; the composition root PixeliaBBS) knows nothing of telnet, and lib/ui holds UI::Modern with its canvas widget and viewer, and UI::Petscii with a screen copy that sends only the differences.