Table of Contents
Tiny BASIC Web, version 0.6
©2025 by Mark Damon Hughes
cyberhole.online/basic/
Text licensed as CC BY-NC-SA Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International license
Code licensed as BSD, see LICENSE.txt
Tiny BASIC Web (TBW hereafter) is an interpreted, interactive BASIC which can be embedded in a web page. The purpose is to make interactive menus and mini-games easy to deploy. It's not a fully-baked programming environment, and not usable on command-line, both of which exist in many other places.
Level 1 supports only numeric or string variables of 1-2 chars, string constants. No arrays, functions, labels, or optional items. RND is a pseudo-variable.
Level 1 terminal only supports one physical line for commands or inputs, so maximum 63 chars in my setup. Whether this will be improved in Level 2, or only in uploaded scripts, remains to be seen. Ideally lines should be at least 120 chars, maybe 256.
Level 2 is as below.
Just type. In command mode (after READY or any successful command), up to a screen width of characters can be entered.
Paste (⌘V or ^V) works, but is subject to the same rules as keyboard use: Wrap your lines at 63 chars.
To get your program out, use LLIST, and copy from the "printer" listing that opens below.
You can find out what files exist with DIR
, and choose to load one with LOAD "filename"
.
Once you have a program entered, type RUN
.
NEW
or reload the page to get a blank BASIC again.
<html>
<head>
<title>TinyBasicWeb</title>
<link href='../style.css' rel='stylesheet' type='text/css' />
<script src='../js/mdhutil.js'></script>
<script src='../js/terminal.js'></script>
<script src='js/tbasicweb.js'></script>
</head>
<body onload='tbasicwebinit("terminal", [64,24], [15,24], "myprog.bas")'>
<div id='terminal'></div>
</body>
</html>
You can start with no program ("boot to READY") by changing "myprog.bas"
to null.
Or use a 'run' URL parameter as your BASIC program, change "myprog.bas"
to
new URL(document.location).searchParams.get("run"))
To pack the canvas size correctly, pick sizes you like, run it. The browser console will show Actual charsize=X
. Then change the ones you give in the function, and reload. My initial guess of [64,24], [14,24]
produced Actual charsize=14.40234375
, so I changed width to 15.
{}
is grouping, []
is optional, …
is 0 or more, |
separates options. Case is ignored, but in this grammar UPPER
is keywords, lower
is syntax term.
linenum
:= 1-32767
line
:= linenum statement
label
:= linenum
label
:= linenum|name
name
:= a-z {a-z|0-9}…
: Names can be maximum (L1) 2 chars, (L2) 16 chars.
number
:= [+|-]0-9… [. 0-9…] [E[+|-]0-9…]
string
:= " [any char except "]… "
varname
:= name [$]
: String ($) variables hold 0-255 characters.
varname
:= name [$] [( term {, term}… )]
: Note varname syntax is also used for built-in functions. name cannot otherwise be a reserved word.value
:= number|string
term
:= number|string|varname|(expr)
: All expressions must be parenthesized.
op
:= {+ | - | * | / | % | ^ | = | <> | < | <= | > | >=}
:
%
is integer modulo, ^
is exponent.+
appends, <> | < | <= | > | >=
compares case-insensitively.expr
:= term {op term}…
: Note no operator precedence except parens! Strict left-to-right.
(L2) channel
:= # 0-255
Note: -
cannot be prefix, use (x*-1)
to negate.
Boolean logic: Done with 0 & 1 values. A OR B := (A+B)
, A AND B := (A*B)
, FALSE A := (A=0)
, TRUE A := (A<>0)
.
Use +
as Boolean OR, *
as Boolean AND.
+ OR | | | * AND | ||||
---|---|---|---|---|---|---|
x | y | | | x | y | ||
. | 0 | 1 | | | . | 0 | 1 |
0 | 0 | 1 | | | 0 | 0 | 0 |
1 | 1 | 2 | | | 1 | 0 | 1 |
statement
:= keyword args
, see below
REM
or '
: Starts a comment, runs to end of line.
CLS
: Clear screen.
END
: End program.
GOSUB label
: Temporarily jumps to any line number or label.
GOTO label
: Jumps to any line number or label.
IF term THEN statement1
: Tests term, if non-zero executes statement1. (L2) [ELSE statement2]
executes statement2 if term was zero.
INPUT ["PROMPT",] varname
: Print prompt or "?", request one value for varname.
LET varname = term
: Set variable to term. Note any math expression must be parenthesized.
STR$
).VAL
).{, varname = term}…
: L2 allows multiple assignments on a line.{PRINT|?} [channel ,] {term {{,|;} term}… [{,|;}] }
: Followed by terms, separated by semicolon ;
(no spacing) or comma ,
(which inserts a tab). (L2) channel.
LPRINT ...
: as PRINT, but to line printer.
RETURN
: Returns from GOSUB
, error if not in a GOSUB. Use a variable like rc
to return values.
(L2) * label
: Sets a label. Must be unique across the program.
(L2) BREAK
: Prematurely ends most recent FOR loop.
(L2) DIM varname {, varname}…
: Dimension array variables. Multiple dimensions are allowed, size is elements x 4 for numeric, elements x 1 for strings (stored as UTF-8).
(L2) ERROR "why"
: Error with code 255, message "why".
(L2) FOR varname = term1 TO term2 [STEP term3]
: Starts a loop, sets var to term1, pushes to stack "varname term2 term3 linenum". Continued by NEXT
or terminated by BREAK
.
(L2) INC varname
, DEC varname
: Increment or decrement varname, like LET v=(v+1)
.
(L2) NEXT varname
: If top of stack is varname loop, increments by term3, IF varname <= (if term3 is positive) or >= term2 (if term3 is negative) THEN GOTO linenum ELSE pop from stack.
(L2) PAUSE ms
: Pauses execution for ms
milliseconds.
(L2) TRAP label
: Any error does a GOTO
label. TRAP
negative number disables it.
(L2) ON term GOTO label1 {, labelN}...
: Use term, as integer, to select label to GOTO, from 1 to N. Falls through to next line if term<1
or term>N
.
(L2) ON term GOSUB label1 {, labelN}...
: As above, but GOSUB.
(L2) DATA value {, value}…
: Store data. Note strings must be quoted. DATA isn't strictly needed, use FOPEN, FEOF, FGET to read lines from remote.
(L2) READ varname
: Read next data value & advance pointer.
(L2) RESTORE [label]
: Reset data pointer to start of program or specific label.
(L2) RANDOMIZE n
: Set random number seed to n. Optional since RND is seeded with time at start.
NEW
: Clear program & memory.RUN ["filename"]
: Clear memory. If filename is given, load it (see LOAD below). Start program at first line.LIST [A [, B]]
: List program, from labels A to B.LLIST ...
: as LIST, but to line printer.
CLEAR
: Clear memory.DEL A [, B]
: Delete line, or lines in range.EDIT label
: Put program line in the input buffer.MEMO
: Enter memo mode, can move around screen and "draw" by typing."foo.ext" is a filename. Name can be up to 16 chars (A-Za-z0-9_.-
only, only letter or digit initial) long, case-insensitive (lowercased on server), extension should be "bas" for BASIC, but can be other types for other files.
Regular expression: /^[A-Za-z0-9][A-Za-z0-9_.-]{0,15}$/
Use LOCK
and UNLOCK
to protect your programs when you're not working on them.
DIR ["filespec"]
: List files in TBW/disk
that match text in filename. ""
or no args matches all files.LOAD "filename"
: Clear program & memory, load file TBW/disk/filename
.REDIR url$
: Redirect current page to URL.(L2)
REMOTE url$, stvar, textvar
: Sends URL request, store HTTP status in stvar
, response text in textvar
. For complex returns, use something like:
10 REM url$ returns a DOS filename.
11 REMOTE url$, st, v$
12 IF (st<>200) THEN ERROR ("Network error "+st)
13 REM or use FOPEN, FGET to read file.
14 DEL 20000,20999
15 MERGE v$
16 GOSUB 20000
ERASE "filename"
: Erase file TBW/disk/filename
. Error if file is locked.
FOPEN channel, "filename", "mode"
: Open file TBW/disk/filename
in mode, which is "r" (read), "w" (write), "a" (append). "w" and "a" error if file is locked.
FEOF channel, varname
: Set varname to 1 if EOF, 0 if more data.
FPUT channel, term
: Write value to channel with newline.
FGET channel, varname
: Read one line from channel to varname.
FCLOSE channel
: Close & flush channel.
LOCK "filename", "password"
: Locks a filename with a secret password, which is also up to 16 chars long.
MERGE "filename"
: Load file TBW/disk/filename
, merging lines.
SAVE "filename"
: Save program to file TBW/disk/filename
. Error if file is locked.
UNLOCK "filename", "password"
: Unlocks.
(L2) all except RND
RND
: Pseudo-variable, random number from 0.0 to 1.0 (not inclusive)
ABS(n)
: Absolute value of n.ASC(a$)
: Unicode value of first character in a$.ATN(r)
, COS(r)
, SIN(r)
, TAN(r)
: Arctangent, cosine, sine, tangent of radians r.CHR$(n)
: String containing a Unicode character.ERL(), ERN(), ERM$()
: Error line, number, message.EXP(n)
, LOG(n)
, SQR(n)
: Exponent, natural log, square root of n.INKEY$
: Last key pressedINT(n)
: Truncates n to integer portion.LEN(a$)
: Length of a string.MID$(a$,i,n)
: Substring of a$
from i
through i+n-1
indices. Rightmost n letters is MID$(a$,(LEN(a$)-n),n)
.PI
: Value of π.STR$(n)
: String of a number. Can also do (""+n).TIMER
, DATE$
, TIME$
: Pseudo-variables of current time in float seconds since epoch, local date & time in ISO8601.UCASE$(a$)
, LCASE$(a$)
: Convert string to uppercase, lowercase.VAL(a$)
: Numeric value of a string, 0 if not valid. Can also assign to a numeric var.(L2) Low-rez mixes character and "pixel" graphics. Characters are placed on the screen from 0,0 to LOC(3), LOC(4)
positions. Use PRINT AT(x,y)
to specify location.
Pixel graphics (px,py) have 4 pixels in a 2x2 grid per character, use LOC(3)*2, LOC(4)*2
to get screen size in pixels.
PIX$(n) lets you mix text and graphics, or store a line of pixels in a string.
Drawing characters or pixels offscreen is ignored.
Statements:
CIRCLE px,py,pr,a1,a2
: Draw pixel circle, radius pr
, from radians a1
to a2
(0,0 to get a full circle).DRAWTO px,py
: Draw pixel line.PLOT px,py
: Plot pixel.SOUND dur,freq,vol,type
: Play simple sound in background. dur
is seconds, freq is frequency in hertz (C is 440), vol
is volume from 0.0 to 1.0, type
is 0:sawtooth, 1:sine, 2:square, or 3:triangle.
SOUND 0.25,440,0.5,0
Functions:
COLOR(fg,bg)
: Sets color fg (foreground), bg (background), returns "", useful in PRINT
. COLOR(15,0) resets to normal. Example:
PRINT AT(32,0);COLOR(9,0);PIX$(9);PIX$(6);"EMERGENCY!";PIX$(6);PIX$(9);COLOR(15,0);AT(0,1);
COL | NAME | HEX |
---|---|---|
0 | black | #000000 |
1 | maroon | #800000 |
2 | green | #008000 |
3 | olive | #808000 |
4 | navy | #000080 |
5 | purple | #800080 |
6 | teal | #008080 |
7 | gray | #808080 |
8 | silver | #C0C0C0 |
9 | red | #FF0000 |
10 | lime | #00FF00 |
11 | yellow | #FFFF00 |
12 | blue | #0000FF |
13 | magenta | #FF00FF |
14 | cyan | #00FFFF |
15 | white | #FFFFFF |
AT(x,y)
: Moves cursor to char coordinate x,y
, returns "", useful in PRINT
.
LOC(n)
: Coordinates: n=0: x-coord, n=1: y-coord, n=2: char under cursor, n=3: screen width, n=4: screen height.
PIX$(n)
: Returns Pixel char: n=0-15 with lit quadrants 1 2 / 4 8:
00=#x20 01=#x2598 ▘ 02=#x259d ▝ 03=#x2580 ▀
04=#x2596 ▖ 05=#x258c ▌ 06=#x259e ▞ 07=#x259b ▛
08=#x2597 ▗ 09=#x259a ▚ 10=#x2590 ▐ 11=#x259c ▜
12=#x2584 ▄ 13=#x2599 ▙ 14=#x259f ▟ 15=#x2588 █