The SpecBAS Reference Manual

The Editor

Working with variables

String Functions

Adding some Structure


Maths Functions

Flow control

INPUT and input functions

INPUT functions

Working with Memory Banks and files

Fun with the Filesystem – Packages and more

Filesystem Functions

Memory Bank and Stream Functions

Faffing with fonts

Font Functions

Window/Screen manipulation

Playing with Colours

Graphical things

Turtle Graphics Commands

Turtle Graphics Functions

Spritely sprites

Loading (and working with) graphics files

Graphics functions

Terrific Tilemaps

Tilemap Functions

Sounds Amazing

Miscellaneous commands

Miscellaneous Functions

The Editor

The editor displays your current program. Upon start-up, you will be greeted by the SpecBAS “About” window – press any key to clear it and enter the editor proper.

The window that appears at the bottom of the screen is the “Direct Command” window. Anything you type in here will be acted upon when you press the RETURN key. Try typing CLS 4 followed by the RETURN key. The screen will turn green, and a window at the bottom of the screen will show “0 Ok, 0:1” – this is the error window and that particular error means that all went well. Press any key to clear it.

To show the current program listing, press RETURN without typing anything else. Press it again to hide the listing window.

When a listing is showing, you can use the CTRL key together with UP and DOWN cursors to move the highlight (cyan colour) from line to line. You can also use the CTRL-PgUp and CTRL-PgDn keys to move a page (screen-full) at a time. This highlight indicates the line that will be edited. To edit a line, press the TAB key. To edit a specific line, type its number into the direct command window, and then press TAB. If you also supply a statement number, say 10:2, then the editor cursor will jump to the start of the statement.

When editing, you can use the LEFT, RIGHT, UP and DOWN keys to move around the line. Use SHIFT LEFT/RIGHT to move one word at a time. Use CTRL-HOME and CTRL-END To move to the very start and ends of a line. Editor Direct Command history can be accessed with SHIFT UP/DOWN, to recall previously issued direct commands.

Press RETURN to accept a line. If it is a direct command (starts with a keyword) then it will be executed immediately if there are no errors. If it starts with a line number, then it will be stored away for later, appearing in order on the listing window.

Press ESCAPE to clear the current line.

Finally, by pressing CTRL-SHIFT-Fn (Fn being a function key, F1 to F10) you can set a marker in the listing. To jump to that marker, press CTRL-Fn (the same function key you assigned it to).

Working with variables

LET Variable = expr

LET assigns a value (the result of ‘expr’ above) to a variable. Variables can have names of any length – and can contain spaces and numbers, though cannot start with a number. String variables are denoted by a terminating ‘$’ character.

LIST VAR [array()]

With no parameters specified, this command will produce a list of all declared variables, and their contents. If you specify an array variable with empty brackets appended, such as “a$()” then the contents of that array will be listed.

DIM Variable(numexpr[,numexpr...]) [LEN numexpr]

DIM creates an array of numbers or of strings. Unlike Sinclair BASIC, string arrays are not fixed width. You can create an array of strings of fixed width by specifying the LEN command followed by the desired length. Fixed-width strings cannot be made larger or smaller.

There is no limit to the number of dimensions.

INC numvar[,amount[,start TO end]]

INC will increment the numeric variable specified by the amount specified. If not specified, then the amount is assumed to be 1. Also a range can be optionally added to constrain the variable to a range of values, which wrap when overflowed.

DEC numvar[,amount[,start TO end]]

DEC will decrement, using the same syntax as INC.

SWAP <numvar,numvar|strvar,strvar>

SWAP will exchange two variables. Cannot be used on array variables.


Clears all variables. Also clears the GO SUB stack and any ON assignments, and clears the screen. Can also be used to clear the error status with CLEAR ERROR, see ON for more details.

READ [LINE] variable[, [LINE] variable...]

Interprets an expression held in a DATA statement, and assigns the result to the variable specified. If the LINE qualifier is present, then the variable must be a string variable, and any DATA that is read will be converted to a string, regardless of its original type.

DATA item1[,Item2...ItemN]

Each item following a DATA statement is an expression which evaluates to either string or numeric type. These are read by the READ command in sequence until no more can be found. If the current DATA statement ends, then READ will continue with the next DATA statement in the program.

RESTORE <linenumber|label>

Sets the location of the next DATA statement to be READ from. If no DATA statement exists at this location in the program, RESTORE searches ahead for the next one, if one exists.

ITEM (function)

The ITEM function returns information about the next DATA item to be read. It returns 0 if there is no more data, 1 if the item is numeric and 2 if the item is a string.

SAVE filename$ DATA var/array()

Use this command to save a variable or array to disk for later retrieval. Use empty braces () to specify an array.

LOAD filename$ DATA [var]

Use this command to load a previously saved variable or array. If no variable/array name is specified, then the original name will be used. If it is specified, and it matches the variable type (ie, “a$” will not be be valid for numeric variables or arrays) then the loaded variable will assume that name. If the variable already exists in memory, it will be deleted and the new one will take its place. You do not need to specify the empty braces () for an array – arrays, once saved, cannot be loaded back as simple variables and will always load back as arrays.

String Functions

There should perhaps be a note in here about inline string characters which are specified using the ‘#’ character – ie, #32 which would equal a space character. They can be used in place of strings, and can be prepended and appended to other strings (and other inline strings characters) without a concatenation (‘+’ character). Ie:

LET a$=”Hello”#32”there!”

Would result in a string which contains the words “Hello there!” – note that the #32 has inserted a space.

VAL$ strexpr

VAL strexpr

Returns the result of the expression stored in the string expression parameter. In the case of VAL, the expression must return a numeric result. VAL$ can process either, and always returns the result as a string.

STR$ numexpr

Converts a numerical expression into a string, after evaluating it.

CHR$ numexpr

DCHR$ numexpr

QCHR$ numexpr

FCHR$ numexpr

Returns the character that corresponds to the result of the numerical expression. For example, CHR$ 32 returns the “ “ (space) character, or to look at it another way, a string with the first character (or byte) set to 32. The DCHR$ and QCHR$ functions return the numerical expression as 2-byte (for numbers of 0-0xFFFF) or 4-byte (for numbers 0-0xFFFFFFFF) strings respectively. The latter is especially useful for constructing WINDOW PUT-able graphic strings. FCHR$ takes a floating point value and returns a string of eight bytes which represent that number.

LEFT$(strexpr, count)

Returns the number of characters from the left of the string as a string. For example, LEFT$(“hello”,4) returns “hell”.

RIGHT$(strexpr, count)

As for LEFT$, but for the rightmost characters.


Returns a substring of the string expression, from the given start and count parameters. For example, MID$(“Scunthorpe”,2,4) cannot be printed.


Converts the string expression to uppercase characters and returns it.


Converts the string expression to lowercase characters.

REP$(strexpr, count)

Returns a string that is comprised of the string expression parameter repeated count times. A more “orangey” manual would likely use the example REP$(“hip! ”,2)+” hooray!”.

HEX$ numexpr

Returns the number specified as a string of hexadecimal digits.

BIN$ numexpr

Like HEX$, but returns a string of 1s and 0s, representing a binary sequence.

TRIM$ strexpr

Returns the string supplied, but with all whitespace (characters <= “ “) removed from the start and end of the string.

LTRIM$ strexpr

Returns the string,but with any whitespace at the start stripped off.

RTRIM$ strexpr

As for LEFT$, but removes whitespace from the end of the string.

UDG$ <numexpr|char>

Returns a two-character UDG string. When the parameter is numerical, the string returned is the UDG marker (CHR$ 1) + the char corresponding with the number, such as “A” for 65. If the parameter is a string expression, then the result is again a CHR$ 1, but with the first character of the string appended to create the UDG.

LEN strexpr

Returns the number of characters in the string.

CODE strexpr

DCODE strexpr

QCODE strexpr

FCODE strexpr

CODE returns the ASCII code of the first character in the string parameter. For example, “1” would be 49. In a nutshell, the value of the first character as a byte is returned. DCODE and QCODE perform the same job, but return the value of 2-byte and 4-byte strings (or numbers expressed as two and four bytes). FCODE works with 8-byte strings, which can hold a floating-point value.

POS(substr, strexpr)

Searches the string expression for the first occurrence of the substring and returns the position it occupies, or zero if not found.



Returns a string with padding to the left or right. n$ is the source string, which you want to add padding to. m$ is the padding itself (usually a space, or a “0” in the case of a binary number represented as a string) and c is the number of times to insert or append the padding.

INSERT$ (n$,m$,pos)

Returns the string n$ with m$ inserted at position pos.

ITEM$ (n$,m$)

ITEM$ (n$,m,s$)

Returns an item from a list. By default, the list is separated by the “|” character. The string is broken down by the separator and item m is returned. For example, if n$ is “one|two|three|four” and m is 3, then the result would be “three”. Optionally you can specify a separator in s$.

n|n$ IN [list|ranges]

IN tests the value (n or n$ above) against a list of values or ranges and returns true (1) if it’s present in that list. The list can be a set of strings or values separated by commas, or ranges. A range is depicted by a minimum value, followed by TO and a subsequent maximum value, ie [1 TO 10] which would test that the value lies in the range of 1 to 10. Strings can also be compared, ie [“0” TO “9”]. The minimum or maximum value in a range may be omitted – [1 TO ] would test that the value is greater than 1, and [ TO 199] would test that it is less than 199. More than one range can be listed, separated by commas as for the values shown above.

Adding some Structure

Structures are a nice way to store many items of information in one place – such as coordinates (maybe two values together) or a street address (which might be several strings). Because they’re all stored in one place, they can be manipulated individually and then maybe saved to disk, to be reloaded later, like a database. Structures are assigned to string variables – as they are, as their name suggests, simply strings of bytes then they can hold more than just simple text. Values are constructed of bytes (8 of them, as a matter of fact) and strings can obviously be stored in strings…

Structures are created using the DEF STRUCT command –

DEF STRUCT name(value1, value2…)

Which is to say, if you wanted a structure that stores coordinates, you might define it as

DEF STRUCT coord(x,y)

Which tells SpecBAS that you want to create a structure named “coord” and will hold two values. Now you need to assign that structure to a string variable so you can use it. Use the following:

LET a$=STRUCT coord

And SpecBAS will set this up for you. Inquisitive users may notice that PRINT LEN a$ returns “16” – which, given that each value takes up 8 bytes, indicates how they are stored. Variables that are assigned to structures can still be used as string variables and manipulated like any others – just be aware that if you do mess around with them, you may damage the information stored within.

In order to use the values, you reference them with a “.” between the variable name and the value, like so:

LET a$.x=100

Just like any other numeric variable. String values can be stored, and are declared either as fixed-width or variable-width. To declare a variable-width string value, use

DEF STRUCT mystuct(str$, str2$)

Which will set up the structure to hold two strings. To declare a fixed-width string, use

DEF STRUCT mystruct(str$[length])

Which will force all string operations on that value to always contain length characters – with procrustean assignment being used to trim to that length. Extra bytes at the end of the string will always be replaced with spaces to pad out to the length specified.

Structures can also be assigned to arrays of strings like so:

DIM a$(20) STRUCT mystruct

Which will create an array of 20 strings, each of which are assigned a structure. To use those strings, you can reference them just like string variables with

LET a$(5).str$=”Hello!”

Default values can be assigned when declaring the structure – when a variable is assigned that structure, the initial values contained within will be set accordingly like so:

DEF STRUCT coord(x=100,y=150)

And thereafter, both x and y will be set to 100 and 150 when a string variable is assigned that structure. To set values in one go when assigning, use

LET a$=STRUCT coord(x=75,y=30)

Which will tell SpecBAS that you would like the values 75 and 30 to be assigned to the x and y members immediately. This also takes effect with the array form:

DIM a$(20)=STRUCT mystruct(str$=”Ta-da!”)

Whereupon all members of the array will get the same value for the str$ member.

You can get a list of all declared structures, with their members and any default values, but typing

LIST STRUCT at the editor. You can add a variable to that command, such as


Which will list the structure associated with that variable, or you can list just one structure with “LIST STRUCT structname”.

Finally, you can remove a structure with “ERASE STRUCT structname”.

One note that should be made is that any string variable or string array that is saved with structures assigned will be saved with that information, and that of the structure(s) assigned intact. When re-loaded later, any structures needed will be recreated. If a structure of the same name as that stored with the variable or array already exists, it will be erased and re-created. This has the side-effect of removing structure assignments from existing variables that may already use that structure, unless the original structure is identical to the new one.


RANDOMIZE [numexpr]

Sets the random seed, used by the RND function. If a numeric expression is specified, then the result is used as the seed – this enables you to use a repeatable sequence of random numbers which is useful in procedural work.


Sets the angle types used by the trigonometric functions to degrees. The default is Radians.


As for DEGREES, sets angle measurements to Radians. To convert radians to degrees, use the formula ‘deg=rad*180/PI’.

Maths Functions

DEGTORAD numexpr

Converts the number supplied from degrees to radians. Effectively executes “num*PI/180”, but much faster then the equivalent calculation in BASIC can be performed.

RADTODEG numexpr

As for DEGTORAD, but for the opposite conversion from radians into degrees. Uses the calculation “num*180/PI”.


Takes no parameters, and returns a random number where 0 < RND < 1. To get a random number from a range, try RND * Limit, where limit is the highest number you want to get – ie, for a dice roll, try 1+(RND*6).

SIN numexpr

COS numexpr

TAN numexpr

ASN numexpr

ACS numexpr

ATN numexpr

Trigonometric functions. ASN, ACS and ATN are the inverse of their normal counterparts, ie, ArcSIN, ArcCOS and ArcTAN. All take either degrees or radians as parameters, depending on the angle mode set with either DEGREES or RADIANS.

LN numexpr

Returns the natural logarithm of the numerical expression.

EXP numexpr

Returns the exponent of the expression.

SQR numexpr

Returns the square root of the expression.

SGN numexpr

Returns the sign of the expression, either 0,-1 or 1, if the expression evaluates to zero, a negative number or a positive number respectively.

ABS numexpr

Returns the absolute value of the expression. This will effectively convert a negative number into a positive, and leave a positive number alone.

NOT numexpr

A logical operator – converts a TRUE number into a FALSE (0) number, and a FALSE number into a TRUE number (1).

numexpr OR numexpr

Returns TRUE (1) if either of the numerical expressions evaluate to TRUE (non-zero). This is a logical OR, if you require a bitwise OR then use | to operate on.

numexpr AND numexpr

strexpr AND numexpr

Returns, for two numeric paramters, TRUE (1) if both are TRUE (or non-zero), or FALSE (0) if either are FALSE (0). For the string expression as the first parameter, the result is the empty string (“”) if the numerical expression is FALSE (0), but if TRUE (non-zero), the result is the first string parameter.

As with OR these are logical operators – for a bitwise AND, use &.

numexpr MOD numexpr

Returns the modulus, or whole remainder, of the first numerical expression divided by the second. For example, 20 MOD 15 returns 5.

numexpr XOR numexpr

Performs a bitwise “Exclusive-Or” on the first number with the second. This has the effect of reversing the bits of the first number where the corresponding bits of the second number are set. For example, 255 XOR 255 is 0. 255 XOR 127 is 128 – ie, as bits 0 to 6 are set in 127, then all those bits in the 255 are unset, leaving bit 7 (128) set.

numexpr SHL numexpr

Shifts the bits of the first number to the left by the second. This has the effect of multiplying by two to the power of the second number.

numexpr SHR numexpr

As for SHL, but shifts to the right, which has the effect of dividing by 2 for each bit shifted.

INT numexpr

Rounds the numerical expression towards zero. ie, INT 1.5 is 1, and INT -1.5 is -1.

TRUNC numexpr

As for INT, rounds towards zero, and does the same job as INT.

FLOOR numexpr

Returns the highest integer less than or equal to the numerical expression. For example, FLOOR -2.8 returns 3, and FLOOR 2.8 returns 2.

CEIL numexpr

Rounds upwards to the lowest integer greater than or equal to the numerical expression. For example, CEIL -2.8 returns 2, and CEIL 2.8 returns 3.

ROUND(numexpr, digits)

Rounds to a power of ten. For example, ROUND(1234567,3) returns 1235000 and ROUND(1.234,-2) returns 1.23.

FRAC numexpr

Returns the fractional part of the numerical expression – that is, the part that is below the decimal point. For example, FRAC 12.345 returns 0.345.


Returns the larger of the two values.

MIN(numexpr, numexpr)

Returns the smaller of the two values.

ODD numexpr

Returns TRUE (1) if the numerical expression evaluates to an odd number, or FALSE (0) if it’s even.

EVEN numexpr

Returns TRUE (1) if the numerical expression evaluates to an even number, or FALSE (0) if it’s odd.


Raises base to the power of exponent. The same as the ^ operator.


Returns n squared. Faster than using n^2.


Returns the opposite of TWOPOWER – for example, if n is 128, returns 7. Useful for bitwise calculations.




Swaps component parts of values. WORDSWAP swaps the two words (two-byte values) in a 32bit value, BYTESWAP swaps the bytes in a 16bit value and NIBBLESWAP swaps the two 4bit values in a byte.





Returns the component of either a 32bit number (if using WORD type) or a 16bit number.

POLAR (dx,dy)

Returns the angle (in degrees or radians depending on mode) of the point from the origin at 0,0.


Returns the distance using pythagoras’ theorem of the point at dx,dy from the origin at 0,0.

CLAMP (n, min TO max)

Forces a value, n, into the range of min to max. If n falls outside this range it is set to the minimum or maximum value accordingly.

INRANGE (n, min TO max)

Returns true if min<=n<=max, false if not.

BIT (n,m)

Returns the state of bit m in value n – 1 or 0.

BTSET (n,m)

BTCLR (n,m)

Returns the value n with bit m either set or cleared. For example, setting bit 5 on a value of zero will return 32. Bits are in the range 0 to 31.

Flow control

LABEL @name-str

Defines a label for use with any command that requires a line number to jump to, such as GO TO and GO SUB. Whereas supplying a line number for these commands will work just fine, using a label allows you to specify a statement within a line to jump to.

Labels are defined with the “@” character preceding them, and are referenced as such throughout the program.

RUN [linenum|@label]

Causes execution of the program to begin at the specified line number or label if present, or the beginning of the program if not. Clears the screen, all variables, ON commands and the GO SUB stack before commencing execution.


Halts program execution.


Continues execution at the next statement after the program halted.

IF numexpr THEN statement [ELSE statement] [ENDIF]

Tests the numexpr and if TRUE (greater than zero), executes the statement after THEN. If not, then the statement after ELSE is executed if it exists. IF..THEN..ELSE commands can be nested – if a child-condition doesn’t need an ELSE, but the parent IF does, then ELSE ELSE is permitted. For example:

IF a=1 THEN print “A is 1”: IF b=2 THEN print “B is 2” ELSE ELSE print “A is not 1”.

Finally, ENDIF will signify the end of an IF ... THEN construct – if a condition is met, then an ELSE will cause execution to resume after the ENDIF. If the condition is not met, then any code after ELSE will be executed, otherwise execution will continue after the ENDIF. This allows you to insert many IF ... THEN statements in the same line.

FOR numvar = numexpr TO numexpr [STEP numexpr]

Initialises the numeric variable to the result of the first numexpr, and then continues program execution. Information (the second numeric expression and the STEP numeric expression if present) are stored in the variable.

NEXT numvar

Assuming that the referenced numeric variable has been initialised previously with FOR, it is incremented (or decremented if a negative STEP value was specified) and tested against the TO expression – if the limit has been reached, then program execution continues on the next line, otherwise the statement after the FOR command is executed.

FOR EACH <numvar|strvar> IN array()

Like the FOR .. NEXT loop, this will also loop, but in a different manner – it will iterate through the entire array specified, and place the value of the current array element into the variable specified after EACH. Use NEXT to advance to the next element. You must specify the correct variable name that you used above in order for NEXT to do its job. In this way, you can work on every element of an array as a named variable in your code.

GO TO <numexpr|label>

Re-directs program execution to the line number or label specified.

GO SUB <numexpr|label>

Like GO TO, program execution jumps to the line or label specified, but the current line and statement number is added to the GO SUB stack. This can be used to return to the next statement after the GO SUB later.


If a line/statement location has been pushed onto the GO SUB stack, it is popped off and a jump is made to that position in the program.

DO [WHILE numexpr]

DO marks the start of a block of code which will repeat when LOOP is encountered. You can optionally specify a numeric expression following a WHILE command, which if evaluated TRUE, will cause the block to execute. If FALSE, then program execution continues after the matching LOOP command. DO ... LOOP blocks can be nested.

LOOP [UNTIL numexpr]

Matches with a preceding DO command, and causes program execution to loop back to that command. If the optional UNTIL condition is specified, then looping is only performed if it evaluates to TRUE.


Exits out of a DO ... LOOP block early, resuming program execution at the next statement after the next LOOP command.

ON numexpr [EVERY numexpr] statement

ON ERROR statement

ON MOUSEMOVE statement

ON MOUSEDOWN statement

ON MOUSEUP statement

ON KEYDOWN statement

ON WHEELUP statement

ON WHEELDOWN statement

ON KEYUP statement



Use ON to specify a scheduled event. ON ERROR allows you to branch to your own error handling routines – be aware that you must issue a RETURN when you’re done handling the error, and that applies to all of the commands the follow ON.

MOUSEDOWN, MOUSEUP, MOUSEMOVE events are triggered when a mousebutton is pressed or released, or the mouse moves respectively. Similarly, KEYDOWN and KEYUP are triggered when the user presses a key. The WHEELUP and WHEELDOWN events are triggered when the user rolls the mouse wheel (if present) up or down.

ON numexpr EVERY will evaluate the numeric expression when the second number of frames has elapsed. If EVERY is omitted, then the numeric expression will be evaluated after every statement, and could potentially slow down your code drastically.

All these behaviours can be cancelled and deleted from memory by using the OFF keyword, as shown above.

EXECUTE strexpr

Executes a string of BASIC commands as if entered from a direct command. This is useful for code that needs to be modified at runtime, or for strings of Turtle Graphics commands for creating structured drawings. The TOKEN$ function can be used on the expression to speed up execution, as untokenised BASIC will be tokenised before it is run. Tokenising with the TOKEN$ function will skip this step. Labels can be specified and jumped to within the command string, and you can branch out to the main program with GO SUB. Although GO TO can be used, it is not recommended – the current statement is saved onto the GOSUB stack, and a jump out of the command with GO TO will leave this stack untouched, using memory.

TOKEN$ strexpr (function)

This function will error-check and “tokenise” (a sort of compilation operation) a string into a form suitable for execution in either the EXECUTE command or the VAL and VAL$ functions. It is not necessary to tokenise a string for these commands, but if a string is to be executed repeatedly, it can save considerable time if you do.

DEF PROC name[([REF] var1[,var2...])] ... END PROC

Defines a procedure. A procedure is a stub of code that can be called later to be run, much like a subroutine used by the GO SUB command. The difference between a procedure and a subroutine is that the procedure can have values passed to it in the form of variables. DEF PROC must be followed, after some time, by END PROC. When a DEF PROC statement is encountered by the interpreter, execution jumps to the statement directly after the corresponding END PROC. Procedures can be nested one inside another, but this has no effect on execution – a procedure inside another procedure is simply skipped when the parent procedure is called.

Procedures do not have to be initialised with DEF PROC at runtime – it is sufficient that they exist somewhere inside the program. SpecBAS maintains a list of procedures which is updated before your program is run, so you can store your procedures out of the way at the end of the program should you wish to.

The parameters specified are used just like normal variables. They are local to the procedure, and are discarded when END PROC is executed at the end of the procedure. If a global variable (that is, a variable declared outside of any procedure) has the same name as the parameter, then using that name will indicate the parameter and not the global variable. Other global variables can be used inside procedures. Any variable declared inside a procedure is global by default, and will not be destroyed when the procedure ends. To create a local variable, use the LOCAL command. If a procedure calls another procedure, then the parameters of the parent procedure are visible to the child procedure.

An example of a procedure might be:

10 DEF PROC pythagoras(opposite, adjacent)

20 PRINT SQR((opposite*opposite)+(adjacent * adjacent))


Which would be called using the following code:

PROC pythagoras(10,20)

Which would display the number 22.2306797749979 on the screen.

You can supply parameters by reference rather than passing their values – this will have the effect of using that variable rather than the parameter variable, and any changes made to that variable will be permanent. To do this, use the REF command when declaring the parameter list, like so:

DEF PROC myproc(REF a,b)

When using that procedure, you must pass a variable in place of “a”, like so:

PROC myproc(numvar,2)

Which will pass the variable itself rather than it’s contents. When working with the parameter variable “a” inside the procedure, you will in reality be working on the variable specified, in this case “numvar”. This is a neat way of getting data out of a procedure, or writing a procedure that will operate on a variable’s contents. If your procedure is set up to do so, you can pass the REF command inside the PROC command, like so:

PROC myproc(REF a,2)

Which will force the procedure to work on that variable instead of its value. Assuming of course that your procedure has been written to change that parameter’s value, it will work just as if the definition had specified a REF command.

LOCAL variable

When executed inside a procedure, LOCAL creates a variable that is visible to the procedure, but which will be removed on exit from that procedure. The variable will be visible (like procedure parameters) to any procedures called during procedure execution. Variables created this way are initialised to either 0 or an empty string.

Declaring a LOCAL variable outside of a procedure will create a global variable.


This command terminates a declared procedure. When executed, it causes all local variables and parameters created for that procedure to be removed from the variable list, and execution resume at the statement after the PROC command that called it.

END PROC must be used to terminate the procedure’s structure in the listing; EXIT PROC can be used anywhere in the procedure, any number of times.

PROC name[(parameters)]

Calls a procedure declared elsewhere in the program. Variables are created and added to the variable list and the parameters are assigned to those variables. The return statement is stacked on the GO SUB stack, and execution resumes at the first statement directly after the DEF PROC statement for that procedure.

The PROCID and PROCID$ functions can be used with PROC and CALL – they return the index of the procedure specified, ie PROCID(myproc) will return a value that can be called using PROC PROCID(n;param1,param2…), which is useful for calling procedures based on a value calculated previously. The function PROCID$ must be used where a procedure returns a string value and is CALLed, or the CALL function will return a numeric value instead of a string. Functionally, both PROCID and PROCID$ are identical – their names just inform the CALL function what to expect on return from the procedure.

DEF FN name[(var1[,var2...])] = Expression

Functions are similar to procedures in their syntax form, but execute quite differently. As with procedures, parameters are specified (if desired) and then used inside an expression which is evaluated when the function FN is used. An example might be:

DEF FN pythagoras(opp, adj) = SQR((opp*opp)+(adj*adj))

The two parameters would be used as variables local to the function, and are removed from the variable list after evaluation. As with procedures, global variables can be used inside functions. You cannot reference variables in a DEF FN declaration; all parameters passed are values.

FN can be nested inside other DEF FN commands.

Unlike Procedures, functions must be declared by executing a DEF FN before use. This only needs to be done once – specbas maintains a list of functions which it refers to at runtime.

FN name[(parameters)] (function)

FN calls a previously defined function, and returns its result.

CALL name[(parameters)] (function)

The CALL function acts identically to the PROC command, but has one subtle difference – you are able to return a value from the procedure. On entry, the parameter list is set up, but depending on the name of the procedure, a new variable is also added for you to use. If the procedure name is a numeric variable type (like say, “myproc”) then a numeric variable, result, is available to you. If it’s a string variable type (as in “myproc$”) then a string variable result$ is available. On exit of the procedure, the contents of that variable are returned for use in your expression.

For example,

LET a=CALL myproc(1,2)*100

Will execute the myproc procedure, and then multiply the contents of the result variable by one hundred before storing that result in the numeric variable a. The PROCID and PROCID$ functions can be used as with the PROC command to call a procedure by its index value rather than its name.

PUSH linenumber[,statementnumber]

Adds the specified line number (and statement number if it is specified) to the GO SUB stack. Any RETURN executed will now jump to the location specified. You can query the next location on the stack with two functions – POPLINE and POPST, which return the line number and statement number of the next location to be RETURNed to. POPLINE will remove the item from the stack, while POPST will not. Alternatively, you can use the command:

POP numvar[,numvar]

Which will fill the variables supplied with line and statement number of the topmost stacked location respectively. Any instances of these commands which do not specify the statement number will assume statement 1, the first statement in a line.

INPUT and input functions

The INPUT command is used to get strings and numbers from the user. In its most simplest form, the command


Will halt program execution and flash a cursor similar to the editor cursor at the bottom left of the screen. The user can type in any valid numerical expression (such as 1+1 or the name of a variable, or just a simple number) and the text entered will be evaluated. Likewise, if the command specifies a$ instead of a, then any string can be entered – but this will not be evaluated, as it makes no sense to do so. You can list several INPUT items, all separated by the same print-separators as those used in PRINT, hence the command

INPUT a$;b$;c

Will ask the user for two strings and a number in sequence. You can insert a prompt by adding a string before the variable – INPUT “What is your name? “;a$ which will display at the bottom of the screen before the flashing cursor.

There are various command parameters you can use with INPUT, which can be inserted as with the strings and variables above.

FORMAT will specify a simple mask for the input. The mask parameter is a string, and represents the characters that the user may input in each position in the final string –

INPUT FORMAT “(####) ######”;a$

Will prompt the user for a UK phone-number. The string will be automatically filled with the two bracket characters, and the user will be able to type only numbers (represented by the # characters). The brackets are literals and represent characters that must be in the final string and are non-editable by the user. Alternatives to the # mark are:

A – Allows only alphabetical characters, and converts any inputted to uppercase.

A – Allows only alphabetical characters and converts any inputted to lowercase.

< – Allows any character, but any alphabeticals will be converted to lowercase.

> – Allows any character, and any alphabeticals will be converted to uppercase.

& – Allows any alphabetical character

? – Allows any alpha-numeric character

* – Allows any character.

Any other characters will be interpreted as literals as with the brackets in the example above. To use one of the above list as a literal, precede it in the string with a “\” character.

You can move the INPUT prompt to any place on the screen with the AT and MOVE parameters, which are used identically to the PRINT command’s versions. The colour of the cursor will automatically be changed to match the nearest colours in the colour palette to blue and white; you can change this behaviour by using the CURSOR parameter followed by foreground colour and background colour, separated by a comma. You can specify the colour of the text itself by inserting INK and PAPER commands, again as with the PRINT command.

Finally, for numeric variable INPUTs, you can specify an error return value – if the string entered raises an error when evaluated, the value specified after the ERROR parameter will be returned.



These two commands hide or show the mouse pointer in specbas.


Sets a particular graphic (either as a graphic-string or a graphic bank) as the current mouse pointer. This graphic can be any size. Specifying DEFAULT sets the pointer back to the pointer used when SpecBAS is first started.

You can optionally specify a “hotspot” – the point within the graphic that the mouse pointer’s position lies – using the POINT parameter. For instance, creating a 15x15 pixel-size graphic and setting the hotspot to 7,7 will mean that the centre of that graphic will rest on the pixel the mouse is pointing at.

INPUT functions


Returns, taking into account the shift keys, the last key to be pressed on the keyboard as a single character. Returns an empty string if no keys are pressed.

KEY numexpr

Returns the status of the key whose scancode is represented by the numerical expression. Returns TRUE (1) if pressed, and FALSE (0) if not.



Returns the current mouse coordinates in the SpecBAS window or screen.



Returns the number of pixels the mouse has moved since the last mouse movement. Useful in ON MOUSEMOVE statements.


Returns a number built from the state of the mouse buttons – Starting with 0, add 1 if the left button is pressed, 2 if the right button is pressed and 4 if the middle button is pressed.


Returns the virtual “position” of the mouse wheel. This value is initialised to 0 when a program is run, or a CLEAR command is executed. It is incremented by one when the mouse wheel is rolled down, and decremented by 1 when it is rolled up. Thus, it will be common for the value returned to be less than zero.

Working with Memory Banks and files

Banks are blocks of memory that can hold a number of datatypes, and the BANK command manipulates them all.

Note that all banks (except protected banks, see later) are erased on RUN and CLEAR.

BANK NEW numvar[,size]

Use BANK NEW to create an empty bank ready to put your data in. You can optionally specify a size, but this is not necessary as banks can shrink and grow as you see fit, and automatically expand as you write to them with a STREAM. The numeric variable is necessary to hold the new ID number of the created bank, which you will use to reference the bank in later operations. This ID number will be chosen for you (except when using LOAD BANK – see later).

BANK SIZE id,size


BANK COPY srcID,start,Length TO destID,offset

Resize banks with the SIZE command, and copy one bank to another with the COPY command. The second form of the COPY command allows you to copy only a portion of one bank to another. If the portion copied overruns the end of the destination bank then the destination bank is extended to fit.



Finally, you can erase a bank with the ERASE command. This operation will permanently delete any information the bank is holding. Specifying ALL will remove all banks that are unprotected.



When a RUN or CLEAR command is executed, all banks are cleared with the exception of any banks that have protection. You can use the BANK PROTECT command to protect a bank, and remove protection with the BANK UNPROTECT command. Beware that unprotecting special banks, such as the screen or default font, may crash SpecBAS.


This will either list all the banks currently in memory (if you supply no parameter) or will list detailed information about the specified bank.

LOAD strexpr BANK <id|numvar>

Loads the file specified in the string expression to a memory bank. If the ID number is specified, the bank will be overwritten (if it exists) and created with that ID number if not. If no ID number is specified, one will be chosen for you, and loaded into the numeric variable.

SAVE strexpr BANK id

Saves a bank specified by the id number to a file. Any bank can be saved, regardless of how it was created – whether as a FONT bank, a SCREEN bank or whatever.

POKE id,offset,byteval

DPOKE id,offset,wordval

QPOKE id,offset,longwordval

FPOKE id, offsey, floatval

Sets a byte in a memory bank’s data section at the offset specified to the value specified. The DPOKE, QPOKE and FPOKE versions behave identically, but set two, four and eight bytes respectively. Offset must be in range of the bank’s size, or an error occurs.

POKE$ id,offset,string

Writes the specified string of bytes to the bank specified, at the offset specified. This is a very quick method of writing lots of bytes to a bank.

STREAM NEW numvar,<Bankid|filename>

Streams allow fast reading and writing of memory banks and files. Create a stream with STREAM NEW and access that stream using the value returned in the numeric variable. Specifying a numeric expression will attach that stream to a bank, otherwise a string expression will attach it to a file. If the file does not exist, it will be created only when the stream is written to.

STREAM READ id,strvar,count

STREAM WRITE id,strexpr

STREAM SEEK id,offset

Use STREAM READ to read a set number of bytes from the memory bank or file into the specified string variable. Use STREAM WRITE to write the contents of a string expression to the memory bank or file. You can set the position within the file or memory bank using STREAM SEEK, but specifying a position that is out of the range of the size of the bank or file will result in the position being set to offset 0 (if negative) or the end of the stream if larger than the stream size.


Finally, STREAM CLOSE will close the stream, and end file access if it’s attached to a file.

Fun with the Filesystem – Packages and more

The filesystem allows you to work with files. You might have noticed that you cannot browse your entire hard drive with specbas – only one directory is allocated in your users/username hierarchy (Windows) or your home directory (Linux). Although you can create whatever directory structure you like in there, you cannot navigate outside of that directory. This is to ensure that rogue programs cannot damage your system.

SpecBAS implements two filesystems – the HOST filesystem and PACKAGES. The HOST filesystem is the directory hierarchy mentioned above. PACKAGES are a kind of “virtual” filesystem which is in fact a file itself, treated as a filesystem by SpecBAS. PACKAGEs are useful for distributing your software – all files needed by a program can be bundled into one file which when mounted is treated as a filesystem invisibly. When a package is mounted, all filesystem commands are redirected to that package.

Finally, there are ASSIGNs – these are drive-like (think “C:” in windows/DOS) that are assigned to a directory on your host filesystem. They cannot be assigned to directories in a package. This is mainly so that you can easily access files on the host filesystem while a package is mounted. One useful assign is the “$:” assign – this refers to the current directory in the host filesystem. There are two other permanent assigns – SYS: which refers to the root of the host filesystem, and TEMP: which refers to /temp/ - this is used for unpacking files from a package for the graphics and sound libraries to access.

ASSIGN “source$” TO “directory”

Creates an ASSIGN which points to a location on the host file system, ie ASSIGN “TEMP:” TO “/temp/” will assign the TEMP: drive to the temp folder at the root of the filesystem. Thereafter, any files referenced by the “TEMP:” assign – such as “temp:mypic.bmp” - in their path will refer to the file in the /temp/ directory. This is handy for working on files in the host filesystem while you have a package mounted. An empty directory as the TO parameter will remove the assign from the internal list.


This command will list all currently assigned paths, with their Assign-form (SYS: for example) and the path that they point to.

COPY “source” TO “dest” [OVER]

COPY copies files from the source specification – which can include wildcards such as “*.txt” and “pic?.bmp” to the destination directory. The destination must exist. If the OVER parameter is specified, then files will be overwritten if they exist inside the destination directory, otherwise the operation will fail with an error if files already exist.

MOVE “source” TO “dest” [OVER]

Like COPY, this moves files from one place to another but also deletes the original files. Use with care, especially when specifying OVER.

ERASE “filespec”

ERASE DIR “directory” [ALL]

Deletes files from your hard disk or package. When deleting a directory, SpecBAS will generate an error if it’s not empty. Specifying the ALL parameter removes the contents of the directory recursively before deletion. Use with care!

MAKEDIR directory$

Creates the specified directory, if it doesn’t already exist.

RENAME “source$” TO “dest$”

Renames files and directories. The Source$ can contain wildcards, but be aware that the destination must also contain a matching wildcard. For example, “*.bmp” TO “*.png” is allowed, but “?pic*.bmp” TO “pic*.png” is not allowed.

LOAD filename$

Loads the program specified by the filename into memory. If it was saved with a LINE parameter, then execution will begin at that line. If the file is a package, then it will be mounted and if a program names “autorun” is found in the root of the package, it will be loaded and run.

MERGE filename$

Merges the program specified by the filename into the current program. Lines that have the same line number as lines already present in the current program will replace those lines, otherwise they will be inserted in numerical order. MERGE does not work with packages.

SAVE filename$ [[ASCII] LINE numexpr]

Saves the current program to the filename specified. If LINE is present, then it will be saved with a flag to execute the program from that line when loaded. If you specify ASCII after the filename (but before any LINE item) then the file will be saved as plain text which you can edit in your own editor. Programs saved this way can be loaded back, as long as the header “ZXASCII” is the alone on the first line of the program.

SETDIR strexpr

Sets the current working directory to that specified, if the directory exists.

CAT [filespec$][EXP]

Lists the contents of the current directory to the screen. If the EXP keyword is added, then extra information is added to each entry, such as file size and creation date. The filespec can include wildcards and directories, such as “/temp/*.png”


SpecBAS saves your work whenever you enter or alter a program line, and the RECOVER command will load in the last saved backup.

PACKAGE “filename$”

Opens a package and mounts it, but does not automatically run the “autorun” file within. Useful for modifying a package after it’s been closed.

PACKAGE NEW “filename$”

Creates a new package. If the package already exists, it is deleted and a new package created. If a package is already mounted, it is closed and the newly created one is opened. The new package is mounted ready for use.

PACKAGE ADD “filename$”

Adds a file from the host filesystem (this is the only command which will not use the package as a filesystem at this point).



Write protects (and removes write protecton, respectively) your package. Any attempts to write to or modify a package which is write protected will generate an error.


Closes and un-mounts your package.

Filesystem Functions


Returns the current working directory.

Memory Bank and Stream Functions




FPEEK(bankid, offset)

Returns the value in the bank’s data at the given offset. PEEK returns a byte, DPEEK returns a Word (2 bytes, 0 to 65535) and QPEEK returns a LongWord (4 bytes, or 0 to $FFFFFFFF). FPEEK returns a floating point value, which occupies 8 bytes. They are difficult to construct manually, so use FPOKE$ to create them.


Returns a string from the specified bank, which is composed of the bytes from offset, with a length size.


Returns the size of the stream specified.


Returns the current read/write position within the specified stream.


Returns the size of the memory block in the bank specified.

Faffing with fonts

FONT NEW numvar,width,height,mode[,TRANSPARENT index]

Create a new font with FONT NEW, which returns the bank number in the numeric variable parameter. The mode can be FONT_MONO or FONT_COLOUR, and if colour you can specify an optional transparent colour index – any pixels of that colour in the font’s graphical image will not be drawn. Colour fonts take their colours from the current screen palette.


You can set the transparent index of an already created font using the FONT TRANSPARENT command.


You can delete a font bank with FONT ERASE or BANK ERASE.


After creation (or having been loaded with LOAD BANK), the new font bank needs to be activated as the current font before it can be used, and you do that with FONT command on its own. Any subsequent PRINT commands will then use that font.

Font Functions

UDG <numexpr|strexpr>

For a numeric parameter, returns the address in the current font bank’s memory block of the graphical data for the UDG number supplied. For example, for the UDG associated with “A” you would specify 65 and given an 8x8 font, the offset would be 65*64+(256*64).

For a string parameter, the UDG is assumed to be the first character and therefore specifying “A” as the parameter will be the same as specifying 65 as above.


Returns the Bank ID number of the current font.


Returns the current font character width.


Returns the current font character height.


Returns the type of font in use – 1 for a colour font, and 0 for a mono font.


Returns the transparent index of the current font, or -1 if none exists or the font is MONO type.

Window/Screen manipulation

FPS count

This command sets the number of frames that SpecBAS will try to display every second. The default is 50 frames per second. You can specify a minimum of 1 and a maximum of 200 – though actually achieving 200 frames per second might tax your computer a little. You can add a small speed boost to your program by specifying a low FPS if smooth screen updates are unnecessary. Note that the editor always runs at 50fps, and that any sprites or synchronisation performed with WAIT SCREEN will be affected by this command.

SCREEN <WINDOW|FULL> [width,height]

Decide if SpecBAS should run in a window or occupy the entire screen. If width and height are present, then the size of the window or screen is set accordingly. Windows can be any size, but full-screen resolutions depend on the capability of the host PC’s graphics card.


In order to maintain smooth screen updates, it is sometimes useful to prevent the screen from being drawn to until it’s ready to be displayed. Use SCREEN LOCK to do this, and SCREEN UNLOCK to allow drawing again. While locked, SCREEN UPDATE will force an update of the screen regardless of locked status.

SCREEN GRAB strvar,x,y,w,h [TRANSPARENT index]

This command, along with the WINDOW GRAB command, will get a rectangular section of the screen and store it in a string variable. It is not recommended that you PRINT this variable, as the contents will not make much sense to a human. The string variable will contain a small header and pixels from the grabbed area (including any windows that overlay the selected region), which can be placed in a window with WINDOW PUT command, which will be discussed later. Graphics-in-strings are used in a variety of other commands.

The header consists of the following 10 bytes:

Graphic Width 4 Bytes

Graphic Height 4 Bytes

Transparent colour 2 Bytes

You can convert the width and height to a string of four bytes with the QCHR$ function, and the Transparent colour to a string of two bytes with the DCHR$ function. If no transparent colour is used, then you should write 65535 in this space – two bytes of 255 each. The width and height are multiplied together and compared to the length of the string (without this header) to determine if the string can be used as a graphic.

WINDOW NEW numvar,x,y,w,h [TRANSPARENT index]

Windows are “screens” that are attached to the current screen. They are rendered in z-order, with the main display (window 0) as the first. Use WINDOW NEW to create a new window at coordinates x,y and size w,h in pixels. Optionally, a transparent index can be supplied, which causes any pixels of that colour to be skipped whilst the window is drawing.

Having many visible windows can cause a small performance penalty, so use them with care. Window size is unimportant, however, as portions which are not within the visible screen are not drawn. Windows can be any size.


Issuing a single WINDOW command with a valid window-id number will cause all further output to the screen to be redirected to that window. This includes PRINT commands.


Moves a window to the coordinates specified, relative to the screen. Window 0 cannot be moved.


Resizes a window. This is destructive, and the window contents will require re-drawing afterwards. You cannot resize Window 0.


Alters the z-order of a window. Bringing it to the front will cause it to be drawn last, and therefore in front of all other windows. Sending it to the back will cause it “disappear” behind all other windows. The main screen (window 0) is classed as a window, so can be moved in this way.


This makes a window visible or invisible.Window 0 cannot be hidden.


These commands move the window contents in the x and y axes by the specified amount. SCROLL will move destructively – any contents that move off the visible area are lost, where as ROLL will wrap those contents on at the opposite edge.

WINDOW COPY src_id,x,y,w,h TO dest_id,x,y

Copies a region from the source window to the destination window.

WINDOW GRAB strvar,id,x,y,w,h [TRANSPARENT index]

As for SCREEN GRAB, this will copy a rectangular region of the screen into a string variable with an optional transparent parameter. This, unlike SCREEN GRAB, will not include any overlapping windows, just the window specified.

WINDOW PUT strexpr,id,x,y [ROTATE angle] [SCALE factor]

WINDOW PUT GRAPHIC gfx-id,window-id,x,y [ROTATE angle] [SCALE factor]

Draws a previously GRABbed graphic stored in a string (or a GRAPHIC stored in a graphic bank), at the coordinated specified. You can also specify a rotation angle and scaling factor. Rotation occurs around the central point.


Removes the specified window. If this window was previously focused for drawing, then focus moves back to window 0 (the main screen).

Screen and Window functions

WINw id

Returns the width of the specified window.

WINh id

Returns the height of the specified window.

WINx id

Returns the x-coordinate of the specified window.

WINy id

Returns the y-coordinate of the specified window.


Returns the width of the screen (or host window if in windowed mode).


Returns the height of the screen or host window.


Returns the window ID number of the current drawing window. 0 represents the screen itself.

WINOFF numexpr

Returns the offset inside the screen bank’s memory of the specified window.


Returns the number of screen updates (frames) since SpecBAS was started – this is measured in 50ths of a second.

POINT (x,y)

Returns the palette index of the expressed pixel, relative to the top-left of the current window.

Playing with Colours

INK numexpr

Sets the current INK – the pen colour used to draw text and other graphical constructs.

PAPER numexpr

Sets the background colour for drawn text. This only makes sense for those fonts declared as “MONO” type.

INVERSE numexpr

Provided mostly for compatibility with the original Sinclair BASIC, this when activated by a numerical expression which evaluates TRUE, will swap INK and PAPER values.

OVER numexpr

When activated by the numerical expression evaluating as TRUE (greater than zero), this will cause all pixels drawn to be XOR’d with the one already on the screen at that point. This is the same behaviour as the original Sinclair implementation, but as the screen contains considerable more pixel states than the Spectrum, the results are not as predictable and require careful thought before using.

PALETTE index,<r,g,b|RGB>

Sets the palette entry specified to the colour denoted either by the red, green and blue values passed, or by the value which represents all the channels in one, in $RRGGBB format. Red, Green and Blue can be in the range 0 to 255.

PALETTE HSV index,<h,s,v|HSV>

As above, this sets the palette using Hue, Saturation and Value components rather than RGB values. As hue is specified in the range 0..360, the HSV Value takes the form $HHHHSSVV.

PALETTE <SHL|SHR> amount[,start TO end]

This will cycle the colours of the palette, left or right respectively. If the range “start TO end” is specified, then only those colour indexes inclusive to the range will be cycled. The palette will wrap around as it cycles.


Sets the current screen palette to the default palette – original spectrum colours and the “web safe” palette, with some greyscales.

Colour Functions


Converts the supplied trio of values into a valid $RRGGBB format colour number.

RED numexpr

GREEN numexpr

BLUE numexpr

Extracts the red, green or blue component from a $RRGGBB format colour.

RGB index

Returns the palette entry specified (0 to 255) in $RRGGBB format.

RGBtoHSV numexpr

Converts from $RRGGBB format to $HHHHSSVV format. Hue is in the range 0..360, so needs two bytes to convert properly.

HSVtoRGB numexpr

Converts from $HHHHSSVV to $RRGGBB.

HSVtoINT (hue,saturation,value)

Converts from the HSV Values provided to $HHHHSSVV.

HUE index


VALUE index

Extracts the required Hue, Saturation and Value from a $HHHHSSVV format colour.

HSV index

Returns the $HHHHSSVV value of the palette entry specified.

RGBn numexpr

RGBf numexpr

RGBc numexpr

These functions take a $RRGGBB format colour and attempt to find, in the current palette, the closest, furthest match and the best contrasting colour respectively.

Graphical things

CLS [numexpr]

Clears the current window to the colour specified. If no colour is present, then the last PAPER value is used. Using CLS to change paper colour is non-permanent.

PRINT [[colour-item|expr|location-item]print-sep...]

Displays optional textual items on the screen. Text can be any expression, be it numerical or string. Colour items can be included in the parameter list if desired, and will temporarily affect INK, PAPER, OVER and INVERSE settings. The location of the text can be set with the AT command (which moves text based on a grid whose size is the size of a single character), the MOVE command which uses a pixel-based grid and the TAB command which moves text to a position within the current line.

Print separators are “ ; ” which concatenates strings, “ ” which forces text to appear on a new line, and “ , “ which moves to the next tab-stop.


As for the PRINT command, TEXT puts text on the screen and takes the same parameters. The only difference is that the TEXT command does not wrap text at the screen edges, and does not cause the screen to scroll when text runs off the bottom.

PLOT [colour-item;...]x,y

Draws a single pixel in the current INK colour unless INK is changed in the colour-items parameter.


MOVE x,y


Sets the current PLOT or drawing position. A single parameter will move in the direction of the current turtle heading (see TURTLE GRAPHICS for more info on this system), and two parameters will move as an offset in the x and y axes. Specifying TO moves to an absolute position in the window.

DRAW [[colour-item;...][ TO ]x,y[,angle]...]

Draws a line from the last point plotted (by any of the drawing commands) to an offset specified by x and y, or for a distance of n pixels if only one parameter is specified. See the turtle graphics commands for more info.

For example, DRAW 10,10 will draw to position 110,110 if PLOT 100,100 had been executed beforehand. Specifying the TO command before the coordinates draws from the last point plotted to the coordinate specified. Adding a third coordinate draws an arc which turns through angle degrees (or radians, by default) as it travels from point to point. This parameter retains the bugs found in the original Sinclair implementation; large values cause interesting patterns.

Parameters can be chained; DRAW 10,10;20,20;30,30 will draw three lines to three successive points.

CURVE [colour-item;...] x1,y1 TO x2,y2,n

Draws a bézier curve from the last point plotted, via (but not through) the control point x1,y1 to end at the point x2,y2, with n subdivisions. More subdivisions take longer to calculate, so use with care.

RECTANGLE [colour-item;...]x1,y1 TO x2,y2[,fill$]

Draws a rectangle in the current INK colour (unless changed in the colour-items) from x1,y1 at the top-left corner to x2,y2 at the bottom-right. The coordinates will be reversed if x2 or y2 are less than x1 and y1. Specifying a string as a final parameter indicates the fill pattern, and can be text (which will be rendered in current INK, PAPER and FONT colours) or a previously obtained graphic from a SCREEN GRAB or WINDOW GRAB operation. And empty string will fill with solid colour.

DRAW, like the other commands CIRCLE, ELLIPSE and POLYGON require an initial coordinate to work from, and do not operate from the last point plotted.

CIRCLE [colour-item;]x,y,r[,fill$]

Like RECTANGLE, this draws a circle at the coordinates x,y with a radius r, and as with RECTANGLE, an optional fill string expression can be appended. See above for information about how to use the fill expression.

ELLIPSE [colour-item;]x,y,rx,ry[,fill$]

Similar to the CIRCLE command, but allows you to specify a major and minor radius.

POLYGON [colour-item;]x1,y1 TO x2,y2 TO x3,y3[ TO xn,yn...][,fill$]

Draws a n-sided polygon from a minimum of three points (a triangle is the simplest form of polygon permitted) to any number of points as a maximum. It can be optionally filled using the fill string expression detailed in the DRAW reference.

FILL [colour-item;]x,y[,fill$]

Performs a fast flood-fill starting at the point specified. All pixels touching the destination pixel that share the same colour will be affected. Filling will be done with the currently set INK colour, unless a colour-item in the parameter list specifies otherwise. Again, a texture fill can be used by specifying a fill string expression.

Turtle Graphics Commands

Specbas provides some commands and functions for building LOGO-like sequenced of commands which can be used with the EXECUTE command.

DRAW [colour-item;]n

When only one coordinate parameter is specified with DRAW, it is taken to be a distance amount rather than an actual coordinate. A line is drawn from the last point drawn to the point n pixels along a line in the current turtle heading.



Sets the heading that the turtle is pointing towards. When ROTATE is used alone with a parameter, that value is added (either as degrees or radians) to the heading – positive values turn clockwise, negative anti-clockwise. When TO is specified, then the value is taken as an absolute heading, and the turtle points in that direction.

FACE x,y

Sets the turtle heading so that it points towards the coordinated specified.

Turtle Graphics Functions


Returns the current turtle heading in the currently set units (Degress or Radians).

Spritely sprites

Sprites are graphics that inhabit a window in SpecBAS, and are drawn every frame without needing any code from the user after they have been set up. They can also move, rotate and resize over a period of time if you want.

SPRITE NEW numvar,x,y

Sets up a new sprite. Each sprite is a memory bank, and so the numeric variable will contain the sprite’s bank ID number after creation with this command. The only parameters you need to specify are the x and y coordinates that the sprite will start at. Sprites cannot be used until they have had a graphic frame added to them, and made visible with SPRITE SHOW. Sprites are allocated to the window that is currently active – normally the main screen (Window 0), but you can alter this.

SPRITE ADDFRAME id, gfx$ [PAUSE delay]

Sprites need a graphic to be supplied (as a string, see the graphics commands listed earlier – GRAB and PUT) in order to be displayed. You can add as many frames as you like, and the sprite will animate through each of them each frame update. You can specify an optional delay (in frames, or 50ths of a second) by specifying the PAUSE parameter. The default delay is one frame.



These commands will hide or show the specified sprite. By default, sprites are hidden after creation, which prevents them from showing up on the screen while you add animation frame and movement paths etc.


This will remove all the animation frames from the sprite. Note that this will not delete the sprite from the bank list.

SPRITE MOVE id,dx,dy [STEP px|FRAMES time]

SPRITE MOVE id TO nx,ny [STEP px|FRAMES time]


Use these commands to move sprites to new locations in their window. The first syntax moves the sprite by an offset – dx,dy are the amount of pixels to move. Positive values move to the right and down, negative to the left and up. To set the sprite’s coordinates, use the TO syntax – this causes the sprite to immediately jump to the location you specify, rather than move by an offset. Use the FRAMES parameter to cause the sprite to move to the new coordinates or offset over a period of time measured in 50ths of a second (frames), or the STEP parameter to move to the new destination at a specified rate of pixel per frame. Note that lateral or vertical movements will complete in the same amount of time as diagonal movements. SpecBAS will move the sprites for you each frame, so you can get on with something else while it does it.

Finally, you can move the sprite to a different window by using the TO WINDOW syntax.

SPRITE ROTATE id,angle [FRAMES time]


This command rotates a sprite about its central point. The first syntax takes a delta angle, which is added to the sprite’s own internal angle value – a positive value will rotate to the right (or clockwise) and a negative to the left (counter-clockwise). Using the SPRITE ROTATE command with the TO parameter will take the angle as an absolute value and immediately rotate to that angle. As with the SPRITE MOVE command, you can specify the FRAMES parameter to make the rotation over many frames unattended. If you want to rotate TO a particular angle with the FRAMES parameter, you will also have to specify which direction to rotate – CW to move clockwise, CCW to move counter-clockwise.

SPRITE SCALE id,factor [FRAMES time]

This command, will scale (resize) the sprite. If no FRAMES parameter is used, then the sprite will be instantly scaled to that factor, based on the size of the original frame – so a scaling factor of 1 will draw it at regular size, a factor of 2 will be double size, and 0.5 will be half size. The FRAMES parameter is used in a similar manner to the other commands listed above.


This command will halt any movement, scaling and rotation that a sprite is performing, but will not reset the angle or scale factor.


Erases the sprite from memory, deleting all information (such as animation frames etc). This is the same as using the BANK ERASE command on the bank the sprite inhabits.

Sprite Functions


Returns the address (offset) in the sprite’s memory bank of the numbered frame. Each frame has a header attached before the graphic data – the animation delay (4 bytes), the width (4 bytes), the height (4 bytes) and the transparent index (2 bytes - $FFFF if no transparency specified, otherwise the index of the colour that should not be rendered).


Returns the number of frames the specified sprite has attached to it.





Returns information about the sprite id specified – the position of the sprite, and the width/height of the specified frame.



Returns the scale factor and rotation angle of the specified sprite.


Returns 1 if the sprite is visible (showing, not necessarily actually in the viewable portion of the screen) or 0 is the sprite is hidden.

Loading (and working with) graphics files

SpecBAS can handle a number of graphic file formats – PNG, GIF and BMP are the most common. Files can be any size but must be a paletted format (8Bpp maximum). Use the following commands to load graphics files.

GRAPHIC NEW numvar LOAD filename$ [TRANSPARENT index]

GRAPHIC NEW numvar,width,height [TRANSPARENT index]

GRAPHIC NEW numvar,graphicstr$

These commands all create a new graphic bank in memory, and assign the index number of that graphic to the numeric variable supplied. Note that when supplying a “graphicstr$” (a graphic in a string, such as that created by WINDOW GRAB), the transparent colour index is inherited from the incoming graphic. When creating a graphic bank by specifying the width and height, the background is either the Transparent index if specified, and the current PAPER if not.

The bank’s memory represents the bitmap surface, row by row, top-left to bottom-right.

GRAPHIC LOAD id,filename$ [TRANSPARENT index]

Loads a new graphic to a previously created bank, specified by the ID number.

GRAPHIC GRAB str$,id,x,y,w,h[TRANSPARENT index]

Like the command WINDOW GRAB, this will copy a subsection of the graphic bank specified into the string variable parameter, with an optional transparent colour.

GRAPHIC PUT strvar,n,x,y[,ROTATE a][,SCALE n]

Again like the WINDOW PUT command, this allows you to paste graphics into a graphic bank.


Permanently rotates a graphic bank. This will likely cause the bank to increase in size, so watch out for that. The angle specified depends on the mode used by your program – degrees or radians.


Scales the graphic bank’s surface by the specified amount – 0.5 will scale to half size, 2 will double the size. The change is permanent, so scaling by values <1 will result in loss of some pixels.



These commands will reverse an image in the horizontal axis (with FLIP) and in the vertical axis (with MIRROR). This change, as with rotation and scaling, is permanent.


The ERASE command can be used to delete a graphic bank from memory. Has the same effect as BANK ERASE, but checks if the bank is a graphic and halts execution with an error if not.

GRAPHIC REMAP id [DITHER dither-type]

Causes a graphic bank to inherit the current screen palette, and then remaps all the pixels in the graphic to the closest matches in the new palette. This allows you to draw that graphic onto the screen or a window with minimal difference in colour. Optionally, you can specify a dithering option with the DITHER keyword followed by a number from 0 to 8. This number corresponds to the following constants you can use in place of the number:

0: dtNONE (No dithering)

1: dtRANDOM (Random-dot style dithering)

2: dtDIAGONAL5 (5-level diagonal dithering)

3: dtDIAGONAL9 (9-level diagonal dithering)

4: dtCLUSTERED (Clustered-dot dithering)

5: dtDISPERSED (Dispersed-dot dithering)

6: dtHALFTONE (Haltone-style dithering)

7: dtORDERED16 (16-level ordered dithering)

8: dtORDERED64 (64-level ordered dithering)


Sets a graphic bank’s palette to the default palette – note that this is not the current screen palette.


Changes a colour in the specified graphic’s internal palette. Use the HSV suffix to indicate that the values specified are Hue, Saturation and Value. You can specify individual component of Red, Green, Blue (or Hue, Saturation and value) or you can use the 4-byte long version which is made up of $00RRGGBB (or $HHHHSSVV for HSV values). The index value is the palette entry’s index number, from 0 to 255.

PALETTE COPY id,start,count TO index

Copies the specified palette entries from a graphic’s palette to the specified index (and onwards) of the main screen palette. Use GRAPHIC REMAP to then remap the graphic to the newly created main screen palette.


Like the WINDOW command listed above, this instead of directing all text and graphical output to a window, sends it to a graphic bank’s surface instead. While active, no output will be visible on the screen. Use the regular WINDOW command to return output to the screen or a chosen window.

Graphics functions

GFX$ id (Function)

This function returns the specified bank as a graphic-string suitable for use in any command that requires a graphic – any of the filled ellipse, rectangle, circle or floodfill commands, and the various PUT commands will be able to use the resulting string.




Returns information about the specified bitmap – width, height and current transparent index if set.

GRGB (id, index)

GHSV (id, index)

Returns the specified palette index from a graphic bank’s palette, either as RGB or HSV data. The value returned is in long (4-byte) value format - $00RRGGBB or $HHHHSSVV.


Returns the pixel value at position x,y in graphic specified by the id. Very similar to POINT.

Terrific Tilemaps

Tilemaps are a “map” of tiles – graphical images – that make up a larger image. This is handy for games which display a large amount of images in a map. Tilemaps in SpecBAS can be draw both scaled and rotated like other graphics. Tilemaps require a graphical parameter to be passed when creating them – this should be either a graphic bank or a string-graphic created with string functions. It should hold all the tile graphics needed for the map. All tiles must be the same size, and the graphic should be just large enough to hold them, with no margins. Each tilemap can address up to 1024 different tiles in the graphic.

TILEMAP NEW id, width, height GRAPHIC gfx-id | gfx$, tilewidth, tileheight

Creates a new tilemap in memory. The id parameter should as always be a numeric variable which will hold the memory bank number of the newly created tilemap.Width and Height are the size of the tilemap – the number of tiles it can hold, not the pixel size. The GRAPHIC parameter should point to an already created (and valid, see above) graphic bank or graphic string. The final two parameters are the size of the tiles in the graphic themselves.

TILEMAP GRAPHIC id, gfx-id | gfx$

This command allows you to change the graphical set (and thus the visual look of the tiles) to another graphic. The same rules apply to this graphic as above, though the size of the tiles can change.

TILEMAP SET id,x,y,tile

Sets a particular tile in a tilemap to point to the desired tile.


Clears the tilemap specified. All tiles are re-initialised to -1, indicating no tile.

TILEMAP DRAW id,offx,offy [SCALE n] [ROTATE rx,ry,angle] [TO x,y,w,h]

Draws the selected tilemap to the current window. Offx and Offy are offsets into the tilemap – this indicates where in the tilemap (in pixels, not tiles!) the topleft corner resides. Any scaling and rotation is applied after the offset is applied. Scaling is any number and is used as a multiplier – 2 would double the pixel sizes, 0.5 would halve them. Rotation is different to rotating other objects like graphics, and requires coordinates to centre the rotation about. These coordinates are independent of the offset coordinates. Tiles set to -1 are not rendered.

Tilemap Functions


Returns the tile index at the supplied coordinates in the tilemap specified.

Sounds Amazing

SpecBAS supports sound playback in three ways – Samples, Channels and Music. Samples are stored in memory as banks, and their data represents the sound sample. When a sample is played, you can optionally assign a channel number to that instance of the sample, which you can then control with the CHANNEL commands. You can play up to 128 samples at once, and you can play (and control) more than one instance of the same sample at the same time. Samples are designed to be used for spot effects and small musical jingles – for actual music, use the MUSIC command – this streams larger files from disk, and can only be started and stopped. You can only play one music file at once.

SAMPLE NEW numvar [RATE numexpr] [SIZE numexpr] [BITS numexpr] [STEREO]

SAMPLE NEW numvar,strexpr

Creates a new sample bank, in one of two ways. The simplest is to use the second form, which uses the string expression as a filename, and loads the sample from disk. Supported formats are WAV, AIFF, MP3, MP2, MP1, OGG. Beware that all the sample data is loaded into memory, so it may not be a good idea to load long MP3 files this way. The numeric variable will contain the sample reference number (the Bank ID number).

The first method listed creates a new, empty sample bank and returns its bank ID number in the numeric variable. The parameters listed after allow you to override the default setting (44.1KHz, 16 Bit, Mono and zero bytes in length). Specify the rate in Hz. Bits can be either 8 or 16. Specifying the STEREO parameter will allocate two sound channels for this sample – a stereo sample. The SIZE parameter will create an empty sample of the required size in bytes, otherwise the sample will be zero bytes in length. As Samples are in reality a memory bank, you can use the BANK commands (such as PEEK, POKE and their variants) to make your own samples. You can also use the STREAM commands to write data to the bank.

SAMPLE PLAY numexpr [RATE numexpr] [VOLUME numexpr] [LOOP] [PAN numexpr] [CHANNEL numvar]

Plays a sound sample. The first parameter is the Bank ID number which holds the sample (which must have been created earlier with SAMPLE NEW), and the following optional parameters will change the way the sample is played. You can specify sample RATE (in Hz), the sample VOLUME from 0 (silence) to 1 (full volume). Change the sample panning with the PAN parameter from -1 (left) to +1 (right). Changing the sample rate, voume and panning do not affect the actual sample, just this instance. If none of the parameters are specified, then the original values given the sample when it was created are used.

By using the LOOP parameter, you instruct SpecBAS to loop the sample indefinitely. Finally, you can opt to create a CHANNEL for your sample, which allows you to control the sample’s rate, volume and panning while it is playing. The CHANNEL parameter requires a numeric variable to hold the channel identifier for use with the CHANNEL commands.


Stops the specified sample, which also frees the channel it may be playing on. A stopped sample cannot be restarted.


Deletes the sample from memory, and frees the bank associated with it.



SAMPLE PAN numexpr

These commands all do the same job that the parameters in SAMPLE PLAY do (and take the same values), but affect the sample permanently. If the sample is currently playing, these commands will not take effect until a new instance of the sample is played.



Pauses and resumes a playing channel, created by the SAMPLE PLAY command with the CHANNEL parameter specified. This is particularly useful for samples that loop. If the sample has finished playing (and thus ended the channel’s usefulness), then an error will be generated when trying to access the channel.

CHANNEL RATE channelID,rate

CHANNEL VOLUME channelID,volume

CHANNEL PAN channelID,pan

These commands will change the way the channel specified sounds. You can alter the rate in Hz which will alter the pitch (though also the speed at which it plays), the voume (0 to 1 as for samples) and the panning (-1 to 1, again as for samples). None of these commands make permanent changes to the sample being played.

CHANNEL SEEK channelID, Position

Changes the play position of the channel, allowing you to rewind or fast-forward. The parameter is specified in bytes, and is rounded to the nearest sample.


Stops a currently playing channel, and frees it from memory. You will not be able to work with this channel after using this command.

MUSIC PLAY {filename$|BankID} [PAUSE] [LOOP]

Commences playback (if desired) of a music file – can be .MOD, .S3M, .MO3, .XM, .IT, .MTM, .UMX, .MP3, .MP2, .OGG, .WAV, .AIFF, .MP1 format. Beware that older MOD files with only 15 samples will fail to be recognised, and will need to be converted by a soundtracker program such as Milkytracker on PC, or Protracker under Amiga emulation.

Specifying the PAUSE parameter will load the music file ready for playing, but keep it paused until you’re ready to resume with the MUSIC RESUME command. The LOOP parameter ensures that the music loops around when it finishes playing. If a music track reaches the end and doesn’t loop, then it will be freed and the music will need to be reloaded.



Pauses and resumes the currently playing music file.


Stops the currently playing music file and frees its resources.

MUSIC SEEK numexpr

Changes the currently loaded music file’s play position, in seconds.


Changes the volume of the music playing, from 0 (silence) to 1 (full volume).

Miscellaneous commands

LIST [n [TO m]]

Lists the current program to the screen in a similar format to the spectrum. You can specify either a range of lines (LIST n TO m), or just a starting line (LIST n). Specifying no lines at all means “list the entire program”.

DEBUG linenumber[,statement]

This command will display a list of “codes” which a line or statement is converted into prior to being executed by SpecBAS. Entering a line is a three-step process – the user types in their BASIC code, and SpecBAS then renders that code into “tokens” which represent the words used. Those tokens are then processed into “stacks” of instructions in Reverse Polish Notation, which are later executed one at a time. You can see the results of this process with the DEBUG command. This can be useful when writing optimal code – in general, the less codes displayed for a line, the faster it will execute (though the keywords themselves may take longer than other keywords depending on the amount of work they have to do). This command is used extensively when creating optimisation routines as SpecBAS is developed, and is included as a curiosity for the interested user.


Deletes lines from the program, from “n” through to “m”. Use with care.

RENUMBER [[n TO m] LINE start STEP st]

This command will renumber the program in memory. You can specify a range (n to m) of lines to be renumbered, and the line to start at (LINE start) and the increment (STEP st). Any lines that, as a result of renumbering, gain the same line number as other lines will overwrite those lines. The default LINE and STEP values are 10, so you can just issue the RENUMBER command to quickly renumber the entire program starting at line 10 and working up in steps of 10. Any GO TO and GO SUB commands that use line numbers (ie, not calculated or label jumps) will be updated to point to the correct lines.

REM remarks

Does nothing; is present purely to allow you to insert comments into your program. The entire line from that statement onwards is ignored.

PAUSE numexpr

Halts program execution for a period specified, in frames (50ths of a second). PAUSE 0 will halt forever, until a key is pressed. A keypress will always cut a PAUSE short.

WAIT [SCREEN] numexpr

Like PAUSE, halts execution for a period in milliseconds. 20 milliseconds = 1 frame. Minimum of 1 millisecond pause, but will depend on your host OS as to how accurate the delay will be below a typical minimum (Windows is inaccurate below about 10ms). WAIT cannot be interrupted by a keypress. The optional SCREEN parameter instructs WAIT to pause for at least the number of milliseconds specified, but not to return until the current screen update has completed. This is useful for making smooth animations with variable window and sprite counts, for example.


Takes no parameters, and simply gives up SpecBAS’s current timeslice to the host OS. Tight loops in SpecBAS on a single-core PC can cause delays to other processes and this command will allow them to execute.


Quits SpecBAS.

Miscellaneous Functions




These functions return information on the previous error – the error code, the line it occurred on and the statement within that line where your code failed.


Returns the current time and date as a decimal number – the integer (the part to the left of the decimal point) represents the number of days since 30/12/1899, and the fractional part (that to the right of the decimal point) is the portion of a 24 hour day that has elapsed – if this part was .5, then the time would be 12 noon.

YEAR time

MONTH time

DAY time

Returns the Day number (1 to 28/29/30/31) of the month, or the month number (1 to 12) or the Year based on the numeric time value passed (see above for the time format).

MONTH$ time

DAY$ time

Returns the textual versions of the day (Monday, Wednesday etc) and month (January, February etc) based on the time value supplied.

HOUR time



Returns the Hour, Minute and Second values from the time specified. The Hour will be in 24 hour format, or 0 to 23.