@moonbase-machines/player 0.8.0 → 0.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,15 +1,15 @@
1
1
  #!/usr/bin/env node
2
- // A title played on this machine: its page at http://127.0.0.1:8002/, its Remake and, where its game's data is beside
3
- // it, its Original (/?way=original), on the browser's own player's disk; each file sent with `Cache-Control: no-cache`
4
- // so that a refresh asks for every module again. The folder holds the title's folder, title/ (title.js, its scenes,
5
- // compiled/), and its game's data, <slug>.json, or for a title of its own engine data/; the @moonbase-machines
6
- // packages are served from node_modules at /packages/, where the page's import map finds them. A folder with an
7
- // index.html of its own is served as it is.
2
+ // A title played on this machine: its page at http://127.0.0.1:8002/, its Remake where it has one, and an Original for
3
+ // each game's data beside it (/?way=original, or with more than one /?game=<name>), on the browser's own player's
4
+ // disk; each file sent with `Cache-Control: no-cache` so that a refresh asks for every module again. The folder holds
5
+ // the title's folder, title/ (title.js, its scenes, compiled/), if it is remade, and its games' data, <name>.json
6
+ // each, or for a title of its own engine data/; the @moonbase-machines packages are served from node_modules at
7
+ // /packages/, where the page's import map finds them. A folder with an index.html of its own is served as it is.
8
8
  //
9
9
  // moonbase-play [folder] [port] [host] the folder (play/ unless given)
10
10
  import { createServer } from 'node:http';
11
11
  import { readFile, stat } from 'node:fs/promises';
12
- import { existsSync } from 'node:fs';
12
+ import { existsSync, readdirSync } from 'node:fs';
13
13
  import { extname, join, normalize, resolve, sep } from 'node:path';
14
14
  import { pathToFileURL } from 'node:url';
15
15
 
@@ -24,10 +24,15 @@ const esc = s => String(s).replace(/[&<>"]/g, c => ({ '&': '&amp;', '<': '&lt;',
24
24
 
25
25
  // the page: the title's name, its ways, the player
26
26
  async function page() {
27
- const title = (await import(pathToFileURL(join(root, 'title', 'title.js')).href)).default, slug = title.slug;
28
- const data = existsSync(join(root, slug + '.json')) ? slug + '.json' : 'data/';
29
- const game = data.endsWith('.json') ? JSON.parse(await readFile(join(root, data), 'utf8')) : null;
30
- const name = title.name ?? game?.title ?? slug, original = !!game;
27
+ const remade = existsSync(join(root, 'title', 'title.js'));
28
+ const title = remade ? (await import(pathToFileURL(join(root, 'title', 'title.js')).href)).default : null;
29
+ // (its games: each <name>.json beside the title, its data, and the title's own first)
30
+ const games = await Promise.all(readdirSync(root).filter(f => f.endsWith('.json') && f !== 'package.json').sort((a, b) => (b === title?.slug + '.json') - (a === title?.slug + '.json') || a.slice(0, -5).localeCompare(b.slice(0, -5)))
31
+ .map(async f => ({ name: f.slice(0, -5), data: f, game: JSON.parse(await readFile(join(root, f), 'utf8')) })));
32
+ const slug = title?.slug ?? games[0]?.name, name = title?.name ?? games[0]?.game.title ?? slug;
33
+ // (the ways: the remake, its data the title's own or, for a title of its own engine, data/; an original for each game)
34
+ const ways = [...(title ? [{ label: 'Remake', search: '', module: 'remake/main.js', data: existsSync(join(root, slug + '.json')) ? slug + '.json' : 'data/' }] : []),
35
+ ...games.map((g, i) => ({ label: games.length > 1 ? g.game.title : 'Original', search: !title && !i ? '' : games.length > 1 ? `?game=${g.name}` : '?way=original', module: 'original.js', data: g.data }))];
31
36
  const map = { imports: Object.fromEntries(PACKAGES.map(p => [`@moonbase-machines/${p}/`, `/packages/${p}/`])) };
32
37
  return `<!doctype html>
33
38
  <html lang="en">
@@ -42,15 +47,16 @@ async function page() {
42
47
  <body>
43
48
  <main>
44
49
  <h1>${esc(name)}</h1>
45
- ${original ? '<nav><a href="/">Remake</a><a href="/?way=original">Original</a></nav>' : ''}
50
+ ${ways.length > 1 ? `<nav>${ways.map(w => `<a href="/${w.search}">${esc(w.label)}</a>`).join('')}</nav>` : ''}
46
51
  <section id="player"></section>
47
52
  </main>
48
53
  <script type="module">
49
- const way = new URLSearchParams(location.search).get('way') === 'original' ? 'original' : 'remake';
50
- for (const a of document.querySelectorAll('nav a')) if ((a.search === '?way=original') === (way === 'original')) a.setAttribute('aria-current', 'page');
51
- const [{ play }, { openDisk, titleDisk }] = await Promise.all([import(way === 'original' ? '@moonbase-machines/player/original.js' : '@moonbase-machines/player/remake/main.js'), import('@moonbase-machines/player/disk/disk.js')]);
54
+ const ways = ${JSON.stringify(ways)};
55
+ const way = ways.find(w => w.search === location.search) ?? ways[0];
56
+ for (const a of document.querySelectorAll('nav a')) if (a.search === way.search) a.setAttribute('aria-current', 'page');
57
+ const [{ play }, { openDisk, titleDisk }] = await Promise.all([import('@moonbase-machines/player/' + way.module), import('@moonbase-machines/player/disk/disk.js')]);
52
58
  const at = path => new URL(path, location.origin + '/').href;
53
- await play({ title: at('title/'), data: at(${JSON.stringify(data)}), root: document.getElementById('player'), disk: await openDisk(titleDisk(${JSON.stringify(slug)})),
59
+ await play({ title: at('title/'), data: at(way.data), root: document.getElementById('player'), disk: await openDisk(titleDisk(${JSON.stringify(slug)})),
54
60
  words: { printer: { line: 'What the printer has printed.', print: 'Print', tear: 'Tear off' } } });
55
61
  </script>
56
62
  </body>
@@ -1,4 +1,4 @@
1
- /*! @moonbase-machines/player 0.8.0: MIT, (c) 2026 Mark Wharton (its LICENSE) */
1
+ /*! @moonbase-machines/player 0.9.0: MIT, (c) 2026 Mark Wharton (its LICENSE) */
2
2
  var Di=Object.defineProperty;var ne=(i,e,t)=>()=>{if(t)throw t[0];try{return i&&(e=i(i=0)),e}catch(s){throw t=[s],s}};var z=(i,e)=>{for(var t in e)Di(i,t,{get:e[t],enumerable:!0})};var Qt={};z(Qt,{Machine:()=>zi});import{machine as Ui}from"@moonbase-machines/apple2e";var zi,es=ne(()=>{({Machine:zi}=Ui)});var ts={};z(ts,{blank:()=>qi,placed:()=>Fi,started:()=>ht,units:()=>Wi});import{prodos as Ki}from"@moonbase-machines/apple2e";var qi,Fi,ht,Wi,dt=ne(()=>{({blank:qi,placed:Fi,started:ht,units:Wi}=Ki)});var ss={};z(ss,{driveFiles:()=>Yi,keepSaves:()=>pt,onDisks:()=>Vi,withSaves:()=>ut});import{saves as Hi}from"@moonbase-machines/apple2e";var Yi,pt,Vi,ut,mt=ne(()=>{({driveFiles:Yi,keepSaves:pt,onDisks:Vi,withSaves:ut}=Hi)});var is={};z(is,{COLORS:()=>Ji,colors:()=>xt,paint:()=>Xi,paintHires:()=>gt,paintText:()=>Je,rowStart:()=>Gi,screen:()=>Zi,textRow:()=>Qi});import{screen as _i}from"@moonbase-machines/apple2e";var Ji,xt,Xi,gt,Je,Gi,Zi,Qi,Xe=ne(()=>{({COLORS:Ji,colors:xt,paint:Xi,paintHires:gt,paintText:Je,rowStart:Gi,screen:Zi,textRow:Qi}=_i)});var ns={};z(ns,{pictures:()=>Ie,shapes:()=>tn,windows:()=>sn});import{pictures as en}from"@moonbase-machines/vector";var Ie,tn,sn,Ge=ne(()=>{({pictures:Ie,shapes:tn,windows:sn}=en)});var rs={};z(rs,{bounds:()=>rn,document:()=>on,elements:()=>kt});import{svg as nn}from"@moonbase-machines/vector";var rn,on,kt,wt=ne(()=>{({bounds:rn,document:on,elements:kt}=nn)});var os={};z(os,{C64:()=>cn});import{machine as an}from"@moonbase-machines/c64";var cn,as=ne(()=>{({C64:cn}=an)});var cs={};z(cs,{Printer:()=>Me,WIDTH:()=>fn,bus:()=>yt,paper:()=>bt});import{printer as ln}from"@moonbase-machines/c64";var Me,fn,yt,bt,Ze=ne(()=>{({Printer:Me,WIDTH:fn,bus:yt,paper:bt}=ln)});var ls={};z(ls,{HEIGHT:()=>Ee,LEFT:()=>dn,PALETTE:()=>Qe,TOP:()=>pn,VIC:()=>un,WIDTH:()=>je});import{vic as hn}from"@moonbase-machines/c64";var Ee,dn,Qe,pn,un,je,vt=ne(()=>{({HEIGHT:Ee,LEFT:dn,PALETTE:Qe,TOP:pn,VIC:un,WIDTH:je}=hn)});var fs={};z(fs,{keyboard:()=>xn,pace:()=>gn,painter:()=>kn});import{browser as mn}from"@moonbase-machines/c64";var xn,gn,kn,hs=ne(()=>{({keyboard:xn,pace:gn,painter:kn}=mn)});var ds={};z(ds,{SID:()=>St});import{sid as wn}from"@moonbase-machines/c64";var St,Et=ne(()=>{({SID:St}=wn)});var ps={};z(ps,{ROM_CHOICES:()=>bn,c64Roms:()=>vn,typed:()=>Sn});import{start as yn}from"@moonbase-machines/c64";var bn,vn,Sn,us=ne(()=>{({ROM_CHOICES:bn,c64Roms:vn,typed:Sn}=yn)});var ms={};z(ms,{SECTORS:()=>jn,add:()=>$n,make:()=>Cn,petsciiName:()=>On,read:()=>Ln});import{d64 as En}from"@moonbase-machines/c64";var jn,$n,Cn,On,Ln,xs=ne(()=>{({SECTORS:jn,add:$n,make:Cn,petsciiName:On,read:Ln}=En)});var gs={};z(gs,{keepDrive:()=>jt});import{saves as An}from"@moonbase-machines/c64";var jt,$t=ne(()=>{({keepDrive:jt}=An)});var ws={};z(ws,{play:()=>Tn});var Gt={};z(Gt,{Speaker:()=>we});var Bi=`
3
3
  class SpeakerProcessor extends AudioWorkletProcessor {
4
4
  constructor() { super(); this.queue = []; this.at = 0; this.level = 0; this.port.onmessage = e => this.queue.push(e.data); }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@moonbase-machines/player",
3
- "version": "0.8.0",
3
+ "version": "0.9.0",
4
4
  "description": "The player for Mark Wharton's titles of 1985 to 1995: the Original, a game's own disk on Moonbase's machines, and the Remake, its scenes on an engine; the player's own disk of saves in the browser.",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -14,11 +14,11 @@
14
14
  "moonbase-play": "./bin/moonbase-play.mjs"
15
15
  },
16
16
  "dependencies": {
17
- "@moonbase-machines/apple2e": "0.8.0",
18
- "@moonbase-machines/c64": "0.8.0",
19
- "@moonbase-machines/charset": "0.8.0",
20
- "@moonbase-machines/mos6502": "0.8.0",
21
- "@moonbase-machines/vector": "0.8.0"
17
+ "@moonbase-machines/apple2e": "0.9.0",
18
+ "@moonbase-machines/c64": "0.9.0",
19
+ "@moonbase-machines/charset": "0.9.0",
20
+ "@moonbase-machines/mos6502": "0.9.0",
21
+ "@moonbase-machines/vector": "0.9.0"
22
22
  },
23
23
  "scripts": {
24
24
  "test": "node --test test/*.test.js",