@mojawork/web-components
v0.1.2
Published
mojawork web components: mwork-banner and a complete C64 BASIC V2 interpreter (mwork-basic-interpreter), built with Stencil.
Maintainers
Readme
@mojawork/web-components
Standalone web components (Stencil 4, namespace mwork) — usable in any
framework or in plain HTML.
Live demo: C64 BASIC interpreter in the moja.work Storybook — full docs, playable stories, type your own BASIC.
npm i @mojawork/web-components| Tag | What it is |
| --- | --- |
| <mwork-banner> | Marquee text banner (text, colors, speed as attributes). |
| <mwork-basic-interpreter> | A Commodore 64 with a complete BASIC V2 interpreter, 40×25 PETSCII screen, keyboard, datasette and demo programs. |
Quick start
npm install
npm start # dev server with the demo page (www/)
npm run build # dist + custom elements + docs + www
npm test # unit suite (interpreter core) + browser suite (Playwright)
npm run watch:bas # rebuild on .bas changes (hot-reload workflow)<mwork-basic-interpreter>
<mwork-basic-interpreter
src="my-program.bas"
hot-reload="true"
print-delay="100"
load-delay="3000"
></mwork-basic-interpreter>Click the screen and type — you are at an authentic READY. prompt.
Architecture
The interpreter core is plain, DOM-free TypeScript under
src/components/basic-interpreter/core/ (tokenizer → parser → step-machine
executor, screen/color RAM model, PETSCII tables, key queue, datasette). The
Stencil component is a thin shell: it renders the 40×25 screen model, maps
keydown events to PETSCII and pumps the machine with a statement budget, so
even 10 GOTO 10 stays interruptible (Escape or the STOP button = RUN/STOP).
Language coverage (BASIC V2)
- Statements: PRINT (
;/,zones, TAB, SPC), LET, INPUT, GET, IF..THEN (incl. statement tails), GOTO, GOSUB/RETURN, ON..GOTO/GOSUB, FOR/TO/STEP/NEXT (nested,NEXT A,B), DIM (multi-dimensional), DATA/READ/RESTORE, DEF FN, REM, STOP/CONT, END, CLR, NEW, LIST, RUN, WAIT, POKE/PEEK, SYS/USR (no-op stubs), LOAD/SAVE/VERIFY,LOAD"$"directory. - Functions: ABS ASC ATN CHR$ COS EXP FRE INT LEFT$ LEN LOG MID$ PEEK POS RIGHT$ RND SGN SIN SPC SQR STR$ TAB TAN USR VAL, plus TI/TI$/ST.
- Expressions: full precedence (
-2^2 = -4), string concat/compare, AND/OR/NOT as 16-bit integer ops, typed variables (A,A%,A$, 2-significant-character names), arrays, authentic error messages (?SYNTAX ERROR IN 10,?REDO FROM START, …). - Screen: real screen RAM (PEEK/POKE 1024+), color RAM (55296+), border/ background via POKE 53280/53281, PETSCII control codes (CLR/HOME/cursor/ RVS/colors via Ctrl+1..8, Ctrl+9/0), scrolling, blinking cursor.
- Datasette:
SAVE"NAME"/LOAD"NAME"/VERIFY"NAME"persist to localStorage;LOAD"$"lists the directory.
Documented simplifications: line-input editing instead of the full-screen
editor; LIST echoes the stored source text (no de-tokenization); device I/O
(OPEN/PRINT#/…) raises authentic errors; no SID sound; keyword crunching
means variable names cannot contain keywords (TOTAL = TO TAL) — that one
is authentic.
Properties, methods, events
See the auto-generated
component readme. Highlights:
props src, hot-reload, polling-interval-ms, print-delay, load-delay,
show-toolbar (hide the button bar for embeddings with their own controls);
methods run(), stop(), loadProgram(text), reset(); events
mworkBasicState (idle | running | stopped) and exit (fired by the
EXIT button so the embedding app can close the C64).
Demo programs
Buttons on the component (inline copies in scripts.ts, files in
basic-scripts/ — keep both in sync): Credits, Pacman (fills the
screen with dots via POKE, eats them in a spiral from the outside in — GOSUB
routine, TI-clock pacing — then blinks at the last dot and vanishes), Maze
(10 PRINT CHR$(205.5+RND(1)); : GOTO 20 — stop with STOP), Guess (INPUT
game), Colors (border/RVS demo).
Font
Ships with Pet Me 64 by Kreative Korp,
redistributed unmodified under the Kreative Software Relay Fonts Free Use
License (see src/components/basic-interpreter/assets/PETME64-LICENSE.txt).
Loaded at runtime via the FontFace API; falls back to a monospace stack.
Tests
core/*.unit.test.ts— fast headless suite for the interpreter core (tokenizer crunching, expression precedence, per-statement behaviour, screen/memory model, golden runs of the demo.basprograms).*.cmp.test.tsx— browser tests (Playwright/Chromium) driving the real component: typed keyboard input, INPUT, LOAD/SAVE via localStorage, POKE 53280 border changes, hot reload, STOP.
Browser tests import the built bundle — run npm run build before the first
npm test. A posttest hook restores the full production dist after every
test run (stencil-test emits a pruned dev build).
