A static web page that runs the many BASIC versions of the text game Star Trek on the BASIC dialects they were written for, entered and played like a terminal. The games are not modified or extended: each listing is the transcription of a historical printout.
npm install
npm run dev # http://localhost:5173
npm test # interpreter tests + plays the real listings
npm run build # typecheck, build, then generate a real HTML page per version (see SEO below) in dist/| Piece | Where | What it does |
|---|---|---|
| Listings | programs/<variant-id>/*.bas |
Verbatim transcriptions, plus TRANSCRIPTION-NOTES.md recording method and doubtful spots |
| Catalog | src/catalog.ts |
One entry per version: game, developers, year, BASIC, machine, description, and (if playable) dialect and programs. Drives the timeline and info panel |
| Dialect | src/basic/dialect.ts |
Everything that differs between BASICs at run time: width, print zones, number format, precision, FOR semantics, INP idle value, error text |
| Interpreter | src/basic/{lexer,parser,machine}.ts |
Parses a listing into a common internal form and runs it. Machine also provides direct mode (RUN, LIST, NEW, CONT, immediate statements) |
| Terminal | src/ui/terminal.ts |
The screen and keyboard: echo, Ctrl-C, type-ahead for INP(), output paced at a selectable line speed |
| Timeline (home) | src/ui/timeline.ts |
The home page: a zigzag spine with a card per version in chronological order, extra space for gaps between years. Each card is a link to the version's own URL, so choosing one is ordinary navigation (back button, sharing) |
| Machine view | src/main.ts, src/ui/panel.ts |
A chosen version takes the full width: a back link and earlier/later links, the info plate, and the board. Each version is a real page: /ms-8k-1978/. The layer is a fragment: /ms-8k-1978/#code, #both. Old hash-only links (/#ms-8k-1978) are rewritten to the real URL |
| Board layers | src/main.ts, src/style.css |
Play (the terminal), Original code, and Side by side. Play and Code are the two faces of one board and the paper turns over between them (CSS 3D flip, inert on the hidden face); Side by side lays both flat and needs a wide screen |
| Code layer | src/ui/code.ts, programs/<id>/*.notes.json |
The listing as sections you open one at a time, syntax highlighting, jump links on GOTO/GOSUB targets, optional line-by-line notes, and a marker on the line the machine is running (from Machine.onLine) |
Writing the notes for a listing. Put a <program>.notes.json next to the .bas file and attach it to the program in
src/catalog.ts (notes). It has an overview and a list of sections, each with from (its first line; it runs to the
next section's first line), group, title, summary, and notes ({ "line": 2060, "text": "…" }). test/code.test.ts
checks that every section and note points at a real line inside its own section. Listings without notes still get the code
layer, as one block.
- Analytics. The same Google Analytics 4 property as decwar.org (
G-HLX6HBDBDQ), inindex.html. It is not loaded on localhost, so developing the site never counts as a visit. Moving between versions is apushStatenavigation, which GA4's enhanced measurement records as a page view; nothing else is sent. - One real page per version. The app draws itself in the browser, which would give search engines a single URL. After
vite build,scripts/prerender.mjswritesdist/index.htmlanddist/<id>/index.html, each with its own title, description, canonical URL, Open Graph and Twitter tags, and JSON-LD (VideoGameandBreadcrumbListfor a playable version,WebSiteandItemListfor the home page), plus a<noscript>summary. The tags come fromsrc/seo.ts, which the running app also uses to keep the title and tags right as you move between versions. - What gets indexed. The home page and every playable version. A version whose listing has not been added is
noindex, followand left out ofsitemap.xml; it becomes indexable automatically the day it turns playable. The build also writesrobots.txt(with the sitemap) and404.html; the Worker answers unknown addresses with a real 404. - Share card and icons.
public/og-image.png(1200 x 630),favicon.svgandapple-touch-icon.png. The site address (SITE.origin) is set insrc/seo.ts. - The site is served from the root of its own subdomain, so asset paths are absolute (
base: "/").
Adding a version to the timeline: add a Variant to src/catalog.ts with status: "planned". It appears on the
timeline as a hollow node with its details and a "listing not yet added" screen. To make it playable, transcribe the
listing into programs/<id>/, switch it to status: "playable" with a dialect and programs, and add a Dialect
profile if its BASIC differs. Syntax the current parser doesn't know (e.g. HP A$(1,3) slicing, DEC \ line joining
and statement modifiers) becomes a per-dialect parser hook, designed against that real listing. Translation is to the
shared internal form, never to another text BASIC, so the on-screen listing stays as printed.
- Timeline: seven versions from 1971 to 1978 from the research notes in
Star Trek/. Only the 1978 Microsoft 8K version is playable; the others show their details and "listing not yet added". - Microsoft 8K BASIC (1978): game and instructions run. Every line of both listings parses; 25 seeded random playthroughs of up to 300 commands each raise no BASIC errors.
- Code layer for the 8K game: 28 sections and 120 line notes, written from a reading of the listing.
- Not yet: the other versions' dialects and listings, a proper boot sequence per machine.
- JSON-LD is written into each generated page; it is not rewritten when you move between versions inside the app, which does not matter to a crawler that loads each URL fresh.
- Random-number sequences differ from the original machines, so a given game never replays a historical run.
- Numbers use 24-bit single precision and 6-digit printing to match Microsoft 8K; other dialects will need their own.
- On a phone the 72-column paper is shown at a minimum 8 px font and scrolls sideways slightly, and Side by side is not offered.