BazzBasic
BazzBasic is a BASIC interpreter built to work with the .NET10 Framework.
It supports many of the features of BASIC interpreters from the 80s, but also offers something modern.
Development
So far, EkBass has been responsible for the development of BazzBasic.
BazzBasic is released under the open source MIT license.
Its source code is available and visible to everyone in the project’s GitHub repository.
Currently, the development work is done in the Windows 11 operating system, but with quite a bit of effort it can also be translated to Linux or MacOS.
Main functionalities
Most familiar BASIC features work either completely or almost completely as users of traditional BASIC languages are used to using them.
User-Defined Functions
With or without recursion.
DEF FN factorial$(n$)
IF n$ <= 1 THEN
RETURN 1
END IF
RETURN n$ * FN factorial$(n$ - 1)
END DEF
PRINT FN factorial$(5) ' Output: 120
PRINT FN factorial$(10) ' Output: 3628800SDL2 Graphics
BazzBasic offers a reasonable sampling of SDL2 features.
If your program uses graphic features, SDL2.dll must be in the same directory. This does not apply to console-only programs.
Sounds
BazzBasic includes a sound system built on SDL2_mixer, supporting audio playback with both background and blocking modes.
See Sound Commands
Source Control
With the INCLUDE function, you can split the source code into different files and folders or generate tokenized libraries.
See Preprocessor or Generating libraries
Data types
Unlike many traditional BASIC interpreters, which required strong typing and often separated different data types with suffixes such as $ or %, BazzBasic copes smoothly with untyped data.
Typeless Variables and Constants
Variables automatically hold either numbers or strings:
LET num$ = 42 ' Number
LET text$ = "Hello" ' String
LET mixed$ = "123" ' String (quoted)Arrays
BazzBasic arrays are fully dynamic and support numeric, string, or mixed indexing.
DIM MyArray$
MyArray$("name") = "John Smith"
MyArray$("age") = 42
See Arrays
Getting Started
More Resources
BazzBasic size
Currently, BazzBasic requires about 70 megabytes + SDL2.dll
PublishTrimmed=true would reduce its size, but thorough testing is needed first.
BazzBasic includes .NET 10 assemblies during compilation, which affects the file size.
.NET 10, although a bit bulky, still offers compatibility far into the future.,
Contact
Author of BazzBasic is Kristian Virtanen.
Email: krisu.virtanen@gmail.com
Url: https://github.com/EkBass/BazzBasic
License
BazzBasic is released under MIT license:
MIT License
Copyright (c) 2026 Kristian Virtanen
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Installation
Download binary
- Download BazzBasic binary from GitHub Releases.
- Extract the “.zip” package to a folder of your choice.
Firewall issues
Since BazzBasic is built around .NET 10 and it is still a fairly recent project, Windows Firewall or third-party security programs may give a warning about it the first time you use it.
However, by switching to the GitHub release and providing the correct metadata during the compilation phase, these warnings can be reduced in the future.
The truth is, however, that open source projects that use .NET platforms will always suffer from this problem to some extent.
Run BazzBasic IDE
- Browse to folder where you extracted bazzbasic.exe
- Double-click bazzbasic.exe and IDE opens.
- The integrated IDE which comes with BazzBasic is very basic and simple.
In order you to run your BazzBasic code with built-in IDE, you must save your file first and then press F5 to run it.
Use external IDE
- BazzBasic syntax highlighting is also available for notepad++, Geany and Visual Studio Code.
- Get config files for syntax support from here.
- Adjust your editor to launch bazzbasic.exe <filename.bas>
Use with terminal
- bazzbasic.exe launches BazzBasic IDE
- bazzbasic.exe <filename.bas> launches your BazzBasic code
- bazzbasic.exe -exe <filename.bas> generates executable from filename.bas
- _bazzbasic.exe -lib <filename.bas> generates a tokenized library from filename.bas
Source
- BazzBasic source code is released under MIT license and it is available at github
- Repository is a Visual Studio 2026 project.
IDE Usage
BazzBasic includes a simple integrated development environment (IDE).
Starting the IDE
Run BazzBasic.exe without any arguments to open the
IDE.
Editor Features
- Syntax highlighting for BazzBasic keywords
- Line numbers for easy navigation
- Multiple tabs for working with several files
Keyboard Shortcuts & Menu Map
| Menu | Shortcut | Action | CLI option |
|---|---|---|---|
| File | Ctrl+N | New file | BazzBasic.exe |
| File | Ctrl+O | Open file | none |
| File | Ctrl+S | Save file | none |
| File | Ctrl+Shift+S | Save As | none |
| File | Ctrl+W | Close tab | none |
| File | Alt + F4 | Exit | none |
| Edit | Ctrl+F | Find | none |
| Edit | Ctrl+H | Replace | none |
| Run | F5 | Run Program | BazzBasic.exe file.bas |
| Run | none | Compile as Exe | BazzBasic.exe -exe file.bas |
| Run | none | Compile as Library (.bb) | BazzBasic.exe -lib file.bas |
| Help | none | About | BazzBasic.exe -v |
| Help | none | Beginner’s Guide[1] | BazzBasic.exe -guide |
| Help | none | Check For Updates | BazzBasic.exe -checkupdates |
[1] Opens BazzBasic-Beginners-Guide/releases in default www-browser.
Running Programs
Press F5 to run the current program. A console window will open showing the output.
If there are errors, they will be displayed with line numbers.
Creating Standalone Executables
BazzBasic can package your BASIC program into a standalone .exe file.
Usage
bazzbasic.exe -exe yourprogram.bas
This creates yourprogram.exe in the same folder as the .bas file.
Required Files for Distribution
The standalone exe needs only one additional file:
| File | Required | Purpose |
|---|---|---|
| yourprogram.exe | Yes | Your packaged program |
| SDL2.dll | Yes | Graphics and input |
| SDL2_mixer.dll | Yes | Audio |
Your assets:
| File | Required | Purpose |
|---|---|---|
| .png, .bmp | If used | Image files |
| .wav, .mp3 | If used | Sound files |
Minimal Distribution
mygame/
├── yourprogram.exe
└── SDL2.dll
Distribution with Assets recommendation
mygame/
├── yourprogram.exe
├── SDL2.dll
├── images/
│ ├── player.png
│ └── enemy.png
└── sounds/
├── shoot.wav
└── music.mp3
Where to Find SDL2.dll
Binary download:
If you downloaded the binary file, bazzbasic.exe the required SDL2.dll in in the same folder.
If you build from the source:
After building BazzBasic, SDL2.dll is in:
BazzBasic\bin\Debug\net10.0-windows\
Or after publishing:
BazzBasic\bin\Release\net10.0-windows\publish\
Copy SDL2.dll alongside your packaged exe.
Console Window
The standalone exe runs with a console window visible. This is
intentional for showing error messages.
A feature with what to hide console is coming on version 1.0
Notes
- The packaged exe contains the full BazzBasic interpreter
- File paths in your BASIC code are relative to the exe location
- INCLUDE files are processed at packaging time (embedded in exe)
.NET Runtime Requirement
The packaged exe inherits the same runtime requirements as the BazzBasic.exe used to create it:
- If using release build: Target machine needs .NET 10 runtime
- If using self-contained publish: No runtime needed (larger file size)
To create a fully self-contained BazzBasic for packaging:
dotnet publish -c Release -r win-x64 --self-contained true
Then use that published BazzBasic.exe for packaging your programs.
Creating Libraries
BazzBasic supports pre-compiled libraries (.bb files)
for code reuse. Libraries contain tokenized functions that load faster
than source files and use automatic namespace prefixes to prevent naming
conflicts.
What is a Library?
A library is a collection of user-defined functions compiled into a
binary format. When you create a library: - Source code is tokenized
(converted to internal format) - Function names get a prefix based on
the filename - The result is saved as a .bb file
Creating a Library
Step 1: Write your library source
Libraries can only contain DEF FN functions. No
variables, constants, or executable code outside functions.
REM MathLib.bas - A simple math library
DEF FN add$(x$, y$)
RETURN x$ + y$
END DEF
DEF FN multiply$(x$, y$)
RETURN x$ * y$
END DEFStep 2: Compile the library
bazzbasic.exe -lib MathLib.bas
Output:
Created library: MathLib.bb
Library name: MATHLIB
Size: <size> bytes
The library name is derived from the filename (uppercase, without extension).
Using a Library
Include the library and call library functions with the
FN keyword using the library prefix:
INCLUDE "MathLib.bb"
LET a$ = 5
LET b$ = 3
PRINT "5 + 3 = "; FN MATHLIB_add$(a$, b$)
PRINT "5 * 3 = "; FN MATHLIB_multiply$(a$, b$)Output:
5 + 3 = 8
5 * 3 = 15
Naming Convention
| Source file | Library name | Function prefix |
|---|---|---|
| MathLib.bas | MATHLIB | MATHLIB_ |
| StringUtils.bas | STRINGUTILS | STRINGUTILS_ |
| MyGame.bas | MYGAME | MYGAME_ |
Original function add$() becomes
MATHLIB_add$() when compiled from MathLib.bas.
Accessing Main Program Constants
Libraries cannot define constants, but library functions can access constants defined in the main program:
REM Main program
LET APP_NAME# = "MyApp"
LET APP_VERSION# = "1.0"
INCLUDE "Utils.bb"
PRINT FN UTILS_getAppInfo$() ' Can use APP_NAME# and APP_VERSION#REM Utils.bas - Library source
DEF FN getAppInfo$()
RETURN APP_NAME# + " v" + APP_VERSION#
END DEFLibrary Rules
- Functions only — Libraries cannot contain variables, constants, or loose code
- Automatic prefix — All functions get the library name as prefix
- No conflicts — Multiple libraries can have functions with the same base name
- Binary format —
.bbfiles are not human-readable - Version locked — Libraries compiled with one version may not work with others
- Constant access — Library functions can read constants from the main program
Error Handling
Invalid library content:
bazzbasic.exe -lib BadLib.bas
Library validation failed: Line 5: Libraries can only contain DEF FN functions. Found: TOK_LET
Library not found:
Error: Line 1: Library not found: missing.bb
Benefits of Libraries
- Faster loading — Pre-tokenized code loads instantly
- No name conflicts — Automatic prefixes prevent collisions
- Code organization — Separate reusable code from main program
- Smaller files — Binary format is typically 30–50% smaller than source for larger files
Note: For small files with only a few functions, the
.basfile may be smaller than the tokenized.bbfile due to metadata overhead. The size advantage shifts to the tokenized format as file size grows.
Distributing Libraries
When distributing your program with libraries:
MyGame/
├── MyGame.exe (or MyGame.bas)
├── MathLib.bb
├── StringLib.bb
└── SDL2.dll
Libraries must be in the same directory as the main program, or in a path relative to it.
More Command Line Features
Get a link to the BazzBasic Starter’s Guide
bazzbasic.exe -guide
or
bazzbasic.exe -help
Get Version of Your Current BazzBasic
BazzBasic.exe -version
or
BazzBasic.exe -v
Check For New Version Release
BazzBasic.exe -checkupdate
AI assisted learning
I downloaded the current documentation for Claude.AI, ChatGPT and Mistrall Le Chat to review and asked them to develop a guide for the BazzBasic language that works precisely as an aid to artificial intelligence.
This is the end result that all three “were” satisfied with.
In the AI service you prefer, upload it directly as a file, add it as a project file or agent guide.
With this guide, any AI can help you learn or use BazzBasic effectively.
Rosetta Code
Rosetta Code is a programming chrestomathy site — a collection of common programming tasks solved in as many languages as possible. It’s a great way to see how a language thinks and compare it to others you already know.
BazzBasic has its own category on Rosetta Code:
The same examples are also available in the BazzBasic GitHub repository:
BazzBasic Beginner’s Guide
A beginner’s guide to BazzBasic is now available here: BazzBasic_Beginners_Guide.pdf
Markdown version here
This guide covers everything you need to get started: variables, loops, conditions, functions, file handling, JSON, networking, graphics, sound, and more. Each chapter builds on the last, with working example programs throughout.
This is not a complete reference.
It is a starting point.
The full BazzBasic manual covers everything else.
Author: Kristian Virtanen (EkBass)
License: CC BY-ND 4.0
— free to share with attribution, translations permitted, modifications
are not permitted.
Variables & Constants
- Variables store values that can change during program execution.
- Constants store value that can not be changed during execution
Declaration
- Variables and constants must be initialized with
LETbefore they can be used - BazzBasic variables are not typed, but work the same way as in JavaScript, for example.
- A variable needs the suffix $
- A constant needs the suffix #
Variables
' Basic init for variables
LET a$ = "Foo"
PRINT a$ ' Output: "Foo"
LET b$ = 1
PRINT b$ ' Output: 1
LET c$ = 1 + 2
PRINT c$ ' Output: 3Constants
' Basic init for constants'
LET PI# = 3.14159
LET MAX_PLAYERS# = 4
LET GAME_TITLE# = "Space Invaders"LET only when init
' Once variable is initialized, you do not need LET anymore
LET a$ = 1
a$ = 3
PRINT a$ ' Output: 3Unsigned data type
' Variable stores either a number or a text.
' It is ok to change the type of data.
LET a$ = 1
PRINT a$ ' Output: 1
a$ = "Foo"
PRINT a$ ' Output: FooVersatile usage
' Math with variables and multiple inits in single line
LET a$ = 1, b$ = 2
LET c$ = a$ + b$
LET MyConst# = c$ * b$Error situation examples
' Some errors
a$ = 1 ' error: a$ not initialized
LET b# = 1
b# = b# + 3 ' error: Constant b# had value 1 when initialized, not allowed to change anymoreInit with out a value
' If you want just to init var and not give value yet
LET a$ ' declares variable
a$ = 1 ' inits value 1 to variable
LET b# ' works, but is a bit stupid since now b# is constant with value of nothingConcatenated values
LET x$ = 10
x$ += 5 ' 15
x$ -= 3 ' 12
x$ *= 2 ' 24
x$ /= 4 ' 6
PRINT x$ ' 6
LET s$ = "Hello"
s$ += " World"
PRINT s$ ' Hello WorldImportant: Not allowed with constants “#”
Exceptions
FOR and INPUT
When a variable is introduced with a FOR...NEXT or
INPUT command, it does not need to be initialized with
LET:
REM Ok to use without prior LET
INPUT "What is your name? ", name$
FOR i$ = 1 TO 10
PRINT i$
NEXTComparing variables
A comparison is true if: - two string variables are equal - two number variables are equal - the value of the number in the string variable is the same as the number variable
LET a$, b$
a$ = "123" ' a$ has now value "123"
b$ = 123 ' b$ has now value 123
LET c$ = "321" ' c$ is now "321"
' Output of this IF...THEN: Same
IF a$ = b$ then
print "Same"
ELSE
print "Different"
ENDIF
' Output of this IF...THEN: Different
IF a$ = c$ then
print "Same"
ELSE
print "Different"
ENDIF
c$ = 123
' Output of this IF...THEN: Same
IF c$ = b$ then
print "Same"
ELSE
print "Different"
ENDIFNote: Although 123 and “123” produce TRUE in an IF…THEN comparison, it is best to keep numeric variables as numeric and string variables as string.
A comparison between a numeric and string variable is only made if the data type of the variable contents is not the same. This slows down the comparison process if it is done significantly.
Built-in Constants
BazzBasic provides a full range of automatically initialized constants
System: | Constant | Description | |———-|————-| |
PRG_ROOT# | Full path to the program’s base directory | |
BBVER# | BazzBasic version string
(e.g. "1.1d") |
PRINT "Version: "; BBVER# ' Output: 1.1d
PRINT "Root: "; PRG_ROOT# ' Output: C:\path\to\program\Keyboard:
Arrow Keys
KEY_UP# |
KEY_DOWN# |
KEY_LEFT# |
KEY_RIGHT# |
Special Keys
KEY_ESC# |
KEY_TAB# |
KEY_BACKSPACE# |
KEY_ENTER# |
KEY_SPACE# |
KEY_INSERT# |
KEY_DELETE# |
KEY_HOME# |
KEY_END# |
KEY_PGUP# |
KEY_PGDN# |
Modifier Keys
KEY_LSHIFT# |
KEY_RSHIFT# |
KEY_LCTRL# |
KEY_RCTRL# |
KEY_LALT# |
KEY_RALT# |
KEY_LWIN# |
KEY_RWIN# |
Function Keys
KEY_F1# |
KEY_F2# |
KEY_F3# |
KEY_F4# |
KEY_F5# |
KEY_F6# |
KEY_F7# |
KEY_F8# |
KEY_F9# |
KEY_F10# |
KEY_F11# |
KEY_F12# |
Numpad Keys
KEY_NUMPAD0# |
KEY_NUMPAD1# |
KEY_NUMPAD2# |
KEY_NUMPAD3# |
KEY_NUMPAD4# |
KEY_NUMPAD5# |
KEY_NUMPAD6# |
KEY_NUMPAD7# |
KEY_NUMPAD8# |
KEY_NUMPAD9# |
Punctuation Keys
KEY_COMMA# |
KEY_DOT# |
KEY_MINUS# |
KEY_EQUALS# |
KEY_SLASH# |
KEY_BACKSLASH# |
KEY_SEP# |
KEY_GRAVE# |
KEY_LBRACKET# |
KEY_RBRACKET# |
Alphabet Keys
KEY_A# |
KEY_B# |
KEY_C# |
KEY_D# |
KEY_E# |
KEY_F# |
KEY_G# |
KEY_H# |
KEY_I# |
KEY_J# |
KEY_K# |
KEY_L# |
KEY_M# |
KEY_N# |
KEY_O# |
KEY_P# |
KEY_Q# |
KEY_R# |
KEY_S# |
KEY_T# |
KEY_U# |
KEY_V# |
KEY_W# |
KEY_X# |
KEY_Y# |
KEY_Z# |
Number Keys
KEY_0# |
KEY_1# |
KEY_2# |
KEY_3# |
KEY_4# |
KEY_5# |
KEY_6# |
KEY_7# |
KEY_8# |
KEY_9# |
Naming Rules
- Must end with
$(variable) or#(constant) - Can contain letters, numbers, and underscores
- Cannot start with a number
- Case-insensitive
Valid names:
LET score$
LET player1_name$
LET MAX_VALUE#
LET x$Invalid names:
LET score ' Missing suffix
LET 1player$ ' Starts with numberErrors
In case of error, BazzBasic stops with proper error message.
LET a$ = 100 ' ok
b$ = 200 ' Error at line 2: Undefined variable: B$ (use LET for first assignment)Scope
Variables initialized within the main code belong to the same scope.
IF 1 = 1 THEN
LET x$ = 10
END IF
PRINT x$ ' Output: 10 (x$ is still accessible)- Variables initialized and modified in user-defined functions do not belong to the same scope.
- However, global constants are available.
LET a$ = 1
LET b$ = 100 ' Global variable
LET C# = "Foo" ' Global constant
DEF FN test$(a$) ' Local parameter a$ is initialized here
LET b$ = 2 ' Local b$ (separate from global b$)
PRINT b$ ' Output: 2
PRINT C# ' Output: Foo
a$ = a$ * b$ ' Uses local a$ (100) and local b$ (2)
RETURN a$ ' Returns 200
END DEF
PRINT FN test$(b$) ' Output: 200
PRINT a$ ' Output: 1
PRINT b$ ' Output: 100Arrays & JSON
Arrays store collections of values. BazzBasic arrays are fully dynamic and support numeric, string, or mixed indexing.
- Arrays store values that can change during program execution.
- All array names must end with
$.
Initialization
- Arrays must be initialized with
DIMbefore they can be used - Like variables or constants, arrays are not strongly typed
- An array needs the suffix ‘$’.
DIM scores$
DIM names$
DIM matrix$Multiple declarations:
DIM a$, b$, c$Numeric Indexing
Use numbers as indices (0-based):
DIM scores$
scores$(0) = 95
scores$(1) = 87
scores$(2) = 92
PRINT scores$(0) ' Output: 95String Indexing (Associative Arrays)
Use strings as keys:
DIM player$
player$("name") = "Alice"
player$("score") = 1500
player$("level") = 3
PRINT player$("name") ' Output: AliceMulti-dimensional Arrays
Use multiple indices separated by commas:
DIM matrix$
matrix$(0, 0) = "A1"
matrix$(0, 1) = "A2"
matrix$(1, 0) = "B1"
matrix$(1, 1) = "B2"
PRINT matrix$(1, 0) ' Output: B1Mixed Indexing
Combine numeric and string indices:
DIM data$
data$(1, "header") = "Name"
data$(1, "value") = "Alice"
data$(2, "header") = "Age"
data$(2, "value") = 30
PRINT data$(1, "value") ' Output: AliceArray Functions
DELARRAY
Removes the entire array and all its elements:
DIM arr$
arr$("name") = "Test"
arr$(0) = "Zero"
PRINT LEN(arr$()) ' Output: 2
DELARRAY arr$
' Array no longer exists, can be re-declared
DIM arr$
PRINT LEN(arr$()) ' Output: 0DELKEY
Removes an element from the array:
DIM cache$
cache$("temp") = "value"
PRINT HASKEY(cache$("temp")) ' Output: 1
DELKEY cache$("temp")
PRINT HASKEY(cache$("temp")) ' Output: 0HASKEY
Returns 1 if the key exists, 0 otherwise:
DIM config$
config$("debug") = 1
IF HASKEY(config$("debug")) THEN
PRINT "Debug mode is set"
END IF
IF HASKEY(config$("verbose")) = 0 THEN
PRINT "Verbose not set"
END IFJOIN
Merges two source arrays into a destination array. If both arrays
share the same key, src2$ overwrites
src1$.
DIM a$
DIM b$
DIM c$
a$("name") = "Alice"
a$("score") = 100
b$("score") = 999 ' Same key as a$ — this wins
b$("level") = 5
JOIN c$, a$, b$
PRINT c$("name") ' Output: Alice (from a$)
PRINT c$("score") ' Output: 999 (b$ overwrote a$)
PRINT c$("level") ' Output: 5 (from b$)LEN and ROWCOUNT
LEN(arr$()) | Total element count
across all dimensions (note empty parens) |ROWCOUNT(arr$()) | Count of
first-dimension keys only — use for FOR loops over
multi-dim arrays |DIM sounds$
sounds$("guns", "shotgun_shoot") = "shoot_shotgun.wav"
sounds$("guns", "shotgun_reload") = "reload_shotgun.wav"
sounds$("guns", "ak47_shoot") = "shoot_ak47.wav"
sounds$("guns", "ak47_reload") = "reload_ak47.wav"
sounds$("food", "ham_eat") = "eat_ham.wav"
PRINT LEN(sounds$()) ' 5 as full size of arrayas there is total of 4 values in array
PRINT ROWCOUNT(sounds$()) ' 2, "guns" & "food"Practical Examples
Pass values to user-defined functions
Arrays cannot be passed directly to functions. Instead, pass individual elements as values or whole array as JSON string.
As single values
DIM a$
a$("name") = "Foo"
a$("age") = 19
a$(1) = 1
DEF FN func$(a$, b$, c$)
PRINT a$
PRINT b$
PRINT c$
RETURN 0
END DEF
LET b$ = FN func$(a$("name"), a$("age"), a$(1))
' Output:
' Foo
' 19
' 1As JSON
' ==================================================
' Example how to pass array to user-defined function
' Starting from ver. 1.2
' EkBass, public domain
' ==================================================
' User-defined functions
DEF FN ArrayAsParam$(data$)
DIM array$
LET count$= ASARRAY(array$, data$)
LET daString$
daString$ = array$("name") + "\n"
daString$ = daString$ + array$("score") + "\n"
daString$ = daString$ + array$("address,city") + "\n"
daString$ = daString$ + array$("skills,0") + "\n"
daString$ = daString$ + array$("skills,1") + "\n"
RETURN daString$
END DEF
[inits]
DIM player$
player$("name") = "Alice"
player$("score") = 9999
player$("address,city") = "New York"
player$("skills,0") = "JavaScript"
player$("skills,1") = "Python"
LET json$
[main]
json$ = ASJSON(player$)
' json$ now: {"name":"Alice","score":9999,"address":{"city":"New York"},"skills":["JavaScript","Python"]}
[output]
PRINT FN ArrayAsParam$(json$)
END
' Output:
' Alice
' 9999
' New York
' JavaScript
' PythonSimple List
DIM fruits$
LET count$ = 0
fruits$(count$) = "Apple"
count$ = count$ + 1
fruits$(count$) = "Banana"
count$ = count$ + 1
fruits$(count$) = "Cherry"
count$ = count$ + 1
FOR i$ = 0 TO count$ - 1
PRINT fruits$(i$)
NEXTDictionary / Map
DIM translations$
translations$("hello") = "hei"
translations$("goodbye") = "nakemiin"
translations$("thanks") = "kiitos"
INPUT "English word: ", word$
IF HASKEY(translations$(word$)) THEN
PRINT "Finnish: "; translations$(word$)
ELSE
PRINT "Translation not found"
END IF2D Grid
DIM grid$
' Initialize 3x3 grid
FOR row$ = 0 TO 2
FOR col$ = 0 TO 2
grid$(row$, col$) = "."
NEXT
NEXT
' Place some markers
grid$(0, 0) = "X"
grid$(1, 1) = "O"
grid$(2, 2) = "X"
' Print grid
FOR row$ = 0 TO 2
FOR col$ = 0 TO 2
PRINT grid$(row$, col$); " ";
NEXT
PRINT ""
NEXTOutput:
X . .
. O .
. . X
Error Handling
Array Not Declared
scores$(0) = 95
' ERROR: Array not declared, use DIM first: scores$Element Not Initialized
DIM data$
PRINT data$(0)
' ERROR: Array element data$(0) not initializedAlways check with HASKEY or initialize elements before
reading.
Arrays and JSON
BazzBasic arrays map naturally to JSON. Nested JSON objects and arrays become multi-dimensional keys using comma-separated indices.
ASJSON
Converts a BazzBasic array to a JSON string:
DIM player$
player$("name") = "Alice"
player$("score") = 9999
player$("address,city") = "New York"
player$("skills,0") = "JavaScript"
player$("skills,1") = "Python"
LET json$ = ASJSON(player$)
PRINT json$
' Output: {"name":"Alice","score":9999,"address":{"city":"New York"},"skills":["JavaScript","Python"]}ASARRAY
Converts a JSON string into a BazzBasic array. Returns number of elements loaded:
DIM data$
LET count$ = ASARRAY(data$, "{""name"":""Bob"",""score"":42}")
PRINT data$("name") ' Output: Bob
PRINT data$("score") ' Output: 42
PRINT count$ ' Output: 2Nested JSON becomes comma-separated keys:
DIM data$
LET json$ = "{""player"":{""name"":""Alice"",""hp"":100},""skills"":[""fire"",""ice""]}"
ASARRAY data$, json$
PRINT data$("player,name") ' Output: Alice
PRINT data$("player,hp") ' Output: 100
PRINT data$("skills,0") ' Output: fire
PRINT data$("skills,1") ' Output: iceLOADJSON
Loads a JSON file directly into an array:
DIM scores$
LOADJSON scores$, "highscores.json"
PRINT scores$("first,name") ' Output: depends on file contentsSAVEJSON
Saves an array as a formatted JSON file:
DIM save$
save$("level") = 3
save$("hp") = 80
save$("position,x") = 100
save$("position,y") = 200
SAVEJSON save$, "savegame.json"The resulting savegame.json:
{
"level": 3,
"hp": 80,
"position": {
"x": 100,
"y": 200
}
}Practical example: HTTP API + JSON
DIM response$
LET raw$ = HTTPGET("https://api.example.com/user/1")
ASARRAY response$, raw$
PRINT "Name: "; response$("name")
PRINT "Email: "; response$("email")HTTP Headers with Arrays
HTTPGET and HTTPPOST accept an optional headers$ array
as the last parameter. This enables authenticated API calls, custom
content types, and any other HTTP header needs.
DIM headers$
headers$("Authorization") = "Bearer mytoken123"
headers$("Content-Type") = "application/json"
LET raw$ = HTTPGET("https://api.example.com/data", headers$)DIM headers$
headers$("Authorization") = "Bearer mytoken123"
headers$("Content-Type") = "application/json"
DIM body$
body$("model") = "gpt-4.1-mini"
body$("messages,0,role") = "user"
body$("messages,0,content") = "Hello"
body$("max_tokens") = 100
LET raw$ = HTTPPOST("https://api.openai.com/v1/chat/completions", ASJSON(body$), headers$)
DIM result$
LET count$ = ASARRAY(result$, raw$)
PRINT result$("choices,0,message,content")Loading key=value Files into Arrays
FileRead can populate an array directly from a
key=value formatted text file. If the target variable is a
DIM’d array, BazzBasic automatically parses the file
contents line by line into array elements.
DIM config$
LET config$ = FileRead("settings.txt")
PRINT config$("width") ' Output: 800
PRINT config$("height") ' Output: 600Where settings.txt contains:
width=800
height=600
title=My Game
Lines beginning with # are treated as comments and
ignored:
# Game settings
width=800
height=600
# Display
fullscreen=0
.env files
This makes .env files work naturally for storing API
keys and configuration outside of source code:
IF FileExists(".env") = 0 THEN
PRINT "Error: .env file not found"
END
END IF
DIM env$
LET env$ = FileRead(".env")
LET ApiKey# = env$("OPENAI_API_KEY")Where .env contains:
OPENAI_API_KEY=sk-proj-...
ANTHROPIC_API_KEY=sk-ant-...
Important: Add .env to your
.gitignore to keep API keys out of version control.
Operators
Logical Values
TRUE, FALSE
Boolean constants.
LET gameOver$ = FALSE
WHILE NOT gameOver$
' game loop
IF lives$ = 0 THEN gameOver$ = TRUE
WENDArithmetic Operators
| Operator | Description | Example |
|---|---|---|
+ |
Addition | 5 + 3 → 8 |
- |
Subtraction | 5 - 3 → 2 |
* |
Multiplication | 5 * 3 → 15 |
/ |
Division | 10 / 3 → 3.333... |
Comparison Operators
| Operator | Description | Example |
|---|---|---|
= |
Equal to | x = 5 |
<> |
Not equal to | x <> 5 |
< |
Less than | x < 10 |
> |
Greater than | x > 0 |
<= |
Less than or equal | x <= 100 |
>= |
Greater than or equal | x >= 1 |
Logical Operators
| Operator | Description | Example |
|---|---|---|
AND |
Logical AND | x > 0 AND x < 10 |
OR |
Logical OR | x < 0 OR x > 100 |
NOT |
Logical NOT | NOT finished |
String Operators
| Operator | Description | Example |
|---|---|---|
+ |
Concatenation | "Hello" + " " + "World" →
"Hello World" |
Operator Precedence
From highest to lowest:
()- ParenthesesNOT- Logical NOT*,/- Multiplication, Division+,-- Addition, Subtraction=,<>,<,>,<=,>=- ComparisonAND- Logical ANDOR- Logical OR
Comments
BazzBasic supports two comment styles.
REM
Traditional BASIC keyword comment.
REM This is a comment
REM Initialize player position
LET x$ = 100Single Quote
Shorter alternative, works inline too.
' This is a comment
LET x$ = 100 ' Inline commentBoth styles are completely identical in behavior — use whichever you
prefer. Single quote ' is generally preferred for its
brevity.
' ============================================
' player.bas - Player movement logic
' BazzBasic: https://github.com/EkBass/BazzBasic
' ============================================
[inits]
LET x$ = 320 ' Start at center X
LET y$ = 240 ' Start at center YUser Defined Functions
Basic Syntax
Note: Name of user-defined function must have ‘$’ as suffix
DEF FN functionName$(param1$, param2$, ...)
' Function body
RETURN value
END DEFImportant to remember
A user-defined function must always return a value, and BazzBasic
always expects that value to be used — assigned to a variable or passed
to a command like PRINT.
DEF FN double$(x$)
RETURN x$ * 2
END DEF
PRINT FN double$(21) ' ✓ OK - return value goes to PRINT
LET foo$ = FN double$(5) ' ✓ OK - return value stored in foo$
FN double$(21) ' ✗ ERROR - return value has nowhere to goSimple Function
DEF FN double$(x$)
RETURN x$ * 2
END DEF
PRINT FN double$(21) ' Output: 42
PRINT FN double$(5) ' Output: 10Multiple Parameters
DEF FN add$(a$, b$)
RETURN a$ + b$
END DEF
DEF FN multiply$(a$, b$)
RETURN a$ * b$
END DEF
PRINT FN add$(3, 4) ' Output: 7
PRINT FN multiply$(3, 4) ' Output: 12Array data as parameter
Arrays cannot be passed directly to functions. Instead, pass individual elements as values or whole array as JSON string.
As single values
DIM a$
a$("name") = "Foo"
a$("age") = 19
a$(1) = 1
DEF FN func$(a$, b$, c$)
PRINT a$
PRINT b$
PRINT c$
RETURN 0
END DEF
LET b$ = FN func$(a$("name"), a$("age"), a$(1))
' Output:
' Foo
' 19
' 1As JSON
' ==================================================
' Example how to pass array to user-defined function
' Starting from ver. 1.2
' EkBass, public domain
' ==================================================
' User-defined functions
DEF FN ArrayAsParam$(data$)
DIM array$
LET count$= ASARRAY(array$, data$)
LET daString$
daString$ = array$("name") + "\n"
daString$ = daString$ + array$("score") + "\n"
daString$ = daString$ + array$("address,city") + "\n"
daString$ = daString$ + array$("skills,0") + "\n"
daString$ = daString$ + array$("skills,1") + "\n"
RETURN daString$
END DEF
[inits]
DIM player$
player$("name") = "Alice"
player$("score") = 9999
player$("address,city") = "New York"
player$("skills,0") = "JavaScript"
player$("skills,1") = "Python"
LET json$
[main]
json$ = ASJSON(player$)
' json$ now: {"name":"Alice","score":9999,"address":{"city":"New York"},"skills":["JavaScript","Python"]}
[output]
PRINT FN ArrayAsParam$(json$)
END
' Output:
' Alice
' 9999
' New York
' JavaScript
' PythonString Functions
DEF FN greet$(name$)
RETURN "Hello, " + name$ + "!"
END DEF
PRINT FN greet$("Alice") ' Output: Hello, Alice!Functions with Logic
DEF FN max$(a$, b$)
IF a$ > b$ THEN
RETURN a$
ELSE
RETURN b$
END IF
END DEF
DEF FN min$(a$, b$)
IF a$ < b$ THEN
RETURN a$
ELSE
RETURN b$
END IF
END DEF
PRINT FN max$(10, 25) ' Output: 25
PRINT FN min$(10, 25) ' Output: 10Recursive Functions
Functions can call themselves:
DEF FN factorial$(n$)
IF n$ <= 1 THEN
RETURN 1
END IF
RETURN n$ * FN factorial$(n$ - 1)
END DEF
PRINT FN factorial$(5) ' Output: 120
PRINT FN factorial$(10) ' Output: 3628800Scope
User-defined functions have their own local scope that is completely isolated from the main program:
- Function parameters are local to the function
- Variables declared with
LETinside a function are local to that function
- Functions cannot access or modify global variables from the main program
- Parameters are passed by value - changes to parameters don’t affect the original variables
LET b$ = 100 ' Global variable
LET C# = "Foo" ' Global constant
DEF FN test$(a$) ' Parameter a$ is local
LET b$ = 2 ' Local b$ (separate from global b$)
PRINT C# ' Global constants are available
a$ = a$ * b$ ' Uses local a$ (100) and local b$ (2)
RETURN a$ ' Returns 200
END DEFIn this example: - The global b$ has
value 100 - When calling FN test(b$), the
value 100 is passed to parameter a$ -
Inside the function, a new local variable
b$ is created with value 2 - The local b$ is
completely separate from the global b$ - The function
calculates a$ * b$ = 100 × 2 = 200 - The global
b$ remains unchanged at 100
Labels Inside Functions
Functions can have local labels for GOTO/GOSUB:
DEF FN countdown$(n$)
[loop]
IF n$ <= 0 THEN
RETURN "Done!"
END IF
PRINT n$
n$ = n$ - 1
GOTO [loop]
END DEF
PRINT FN countdown$(5)Output:
5
4
3
2
1
Done!
Function Isolation
GOTO and GOSUB inside a function cannot jump outside the function:
[outside_label]
PRINT "Outside"
DEF FN broken$(x$)
GOTO [outside_label] ' ERROR! Label is outside of function
RETURN x$
END DEFThis produces:
GOTO cannot jump outside function: outside_label
This restriction ensures functions are self-contained and predictable.
Practical Examples
Is Even/Odd
DEF FN isEven$(n$)
RETURN MOD(n$, 2) = 0
END DEF
DEF FN isOdd$(n$)
RETURN MOD(n$, 2) = 1
END DEF
FOR i$ = 1 TO 5
IF FN isEven$(i$) THEN
PRINT i$; " is even"
ELSE
PRINT i$; " is odd"
END IF
NEXTOrder of code
Before code can call a user-created function, it must be loaded from the source code.
Wrong
Code below causes error: Error: Line 1: ‘ADD’ is not a valid variable name (must end with $ or #) or keyword
' incorrect way
PRINT FN ADD$(1, 2)
DEF FN ADD($a$, b$)
RETURN a$ + b$
END DEFRight
Code below is valid
' correct way
DEF FN ADD$(a$, b$)
RETURN a$ + b$
END DEF
PRINT FN ADD$(1, 2)Tip
If you have several of your own functions, write them in their own file and include them in the code using INCLUDE right at the beginning of your program.
Control Flow
IF Statements
Block IF
Multi-line conditional with THEN on its own:
IF score$ >= 90 THEN
PRINT "Grade: A"
PRINT "Excellent!"
END IFIF/ELSE
IF age$ >= 18 THEN
PRINT "Adult"
ELSE
PRINT "Minor"
END IFIF/ELSEIF/ELSE
IF score$ >= 90 THEN
PRINT "A"
ELSEIF score$ >= 80 THEN
PRINT "B"
ELSEIF score$ >= 70 THEN
PRINT "C"
ELSEIF score$ >= 60 THEN
PRINT "D"
ELSE
PRINT "F"
END IFOne-line IF
Jump to label based on condition:
IF lives$ = 0 THEN GOTO [game_over]
IF key$ = KEY_ESC# THEN GOTO [menu] ELSE GOTO [continue]
IF ready$ = 1 THEN GOSUB [start_game]FOR Loops
Note: FOR auto-declares the loop variable — no LET needed.
Basic FOR
FOR i$ = 1 TO 10
PRINT i$
NEXTFOR with STEP
FOR i$ = 0 TO 100 STEP 10
PRINT i$
NEXTCounting Down
FOR i$ = 10 TO 1 STEP -1
PRINT i$
NEXT
PRINT "Liftoff!"Nested FOR
FOR row$ = 1 TO 3
FOR col$ = 1 TO 3
PRINT row$; ","; col$; " ";
NEXT
PRINT ""
NEXTWHILE Loops
Repeat while condition is true:
LET count$ = 0
WHILE count$ < 5
PRINT count$
count$ = count$ + 1
WENDInfinite Loop with Exit Condition
WHILE 1
LET key$ = INKEY
IF key$ = KEY_ESC# THEN GOTO [exit]
' Game logic here
WEND
[exit]
PRINT "Goodbye"Labels and GOTO
Labels are marked with square brackets:
[start]
PRINT "Starting..."
GOTO [main]
[main]
PRINT "Main section"
GOTO [end]
[end]
PRINT "Done"
ENDGOSUB and RETURN
Call a subroutine and return:
PRINT "Before subroutine"
GOSUB [greet]
PRINT "After subroutine"
END
[greet]
PRINT "Hello!"
RETURNNested GOSUB
GOSUB [level1]
END
[level1]
PRINT "Level 1"
GOSUB [level2]
PRINT "Back to Level 1"
RETURN
[level2]
PRINT "Level 2"
RETURNVariables as GOTO/GOSUB targets
A variable or constant containing a label string can be used as a jump target:
LET foo$ = "[start]"
LET bar# = "[jump]"
GOTO foo$
[start]
PRINT "[start]"
GOSUB bar#
PRINT "Ending line"
END
[jump]
PRINT "[jump]"
RETURNFunction Scope and Labels
Inside user-defined functions, GOTO and GOSUB can only jump to labels within the same function:
DEF FN test$(x$)
[local_label]
IF x$ < 10 THEN
x$ = x$ + 1
GOTO [local_label] ' OK - within function
END IF
RETURN x$
END DEF
[outside]
' GOTO [outside] from inside the function above would cause an error
PRINT "Outside"END
Terminates program execution.
IF error$ THEN
PRINT "Error occurred"
END
END IF
PRINT "This runs if no error"SLEEP
Pause execution for specified milliseconds.
PRINT "Wait 2 seconds..."
SLEEP 2000
PRINT "Done!"Line Continuation
Long expressions and statements can be split across multiple lines.
BazzBasic figures this out automatically — there is no special
continuation character to remember (no \, no
_, no &).
A newline is treated as a continuation (instead of ending the statement) when either:
- The previous token cannot legally end an expression — a binary operator, comma, compound-assign, or open paren.
- You are inside an open
( ... )pair.
Operator-driven continuation
Any line ending in an “incomplete” token continues on the next line. Empty lines and trailing comments between the parts are tolerated.
LET total$ = price$ * count$ -
discount$
LET msg$ = "Hello, " +
name$ +
"!"
IF score$ >= 0 AND
score$ <= 100 THEN
PRINT "Valid score"
END IF
LET counter$ +=
step$The full list of operators that trigger continuation: +,
-, *, /, %,
=, <>, <,
<=, >, >=,
AND, OR, +=, -=,
*=, /=, and ,.
Note:
MODis a function (MOD(a, b)), not an operator, so it does not trigger continuation. The symbol%does.
Paren-driven continuation
Anything inside an unmatched ( keeps reading until the
matching ), regardless of newlines:
LET dist$ = DISTANCE(
x1$, y1$,
x2$, y2$
)
LET val$ = MAX(
MIN(100, score$),
0
)
DIM grid$
grid$(0,
0) = "X"Both mechanisms can be combined freely:
LET total$ = (
base$ +
tax$ -
discount$
)Watch out
Forgetting to close a ( makes the lexer keep eating
lines until it finds a matching ) (or runs out of source).
The eventual error message can be far from the actual mistake — count
your parentheses if a long file suddenly stops parsing the way you
expect.
See Also
- Operators — comparison and logical operators
- Input Functions — INKEY, KEYDOWN, WAITKEY
- Statements A-Z — PRINT, INPUT, CLS, etc.
Statements A-Z
Action commands that perform operations. For flow control (IF, FOR, WHILE, GOTO, GOSUB) see Control Flow.
CLS
Clear the screen.
CLSCOLOR
Set text foreground and background colors (0-15 palette).
COLOR 14, 1 ' Yellow text on blue background
PRINT "Colorful!"See also: Graphics Commands
INPUT and LINE INPUT
BazzBasic provides two commands for reading user input from the console.
INPUT
Reads user input, splits on whitespace or comma.
INPUT "prompt", variable$
INPUT "prompt", var1$, var2$, var3$
INPUT variable$ ' Uses "? " as default promptLET firstName$, lastName$
INPUT "Enter your name: ", firstName$, lastName$
' User types: Kristian Virtanen
PRINT firstName$ + " " + lastName$
' Output: Kristian VirtanenLINE INPUT
Reads the entire line including spaces.
LINE INPUT "Enter your name: ", name$
' User types: Kristian Virtanen
PRINT name$
' Output: Kristian VirtanenComparison
| Feature | INPUT | LINE INPUT |
|---|---|---|
| Reads spaces | No (splits) | Yes |
| Multiple variables | Yes | No |
| Default prompt | “?” | None |
LOCATE
Move cursor to specified position (1-based row and column).
LOCATE 10, 20
PRINT "Positioned text"Output text and values to the screen.
PRINT "Hello, World!"
PRINT 42
PRINT "Value: "; x$
PRINT "A", "B", "C" ' Tab-separated
PRINT "X="; 10; ' No newline at endEscape Characters
| Escape | Result |
|---|---|
\" |
Quote |
\n |
New line |
\t |
Tab |
\\ |
Backslash |
PRINT "He said, \"Hello\"" ' Output: He said, "Hello"
PRINT "Line1\nLine2"SHELL
Sends a command to the system command interpreter.
Optional timeout parameter in milliseconds (default: 5000).
LET a$ = SHELL("dir *.txt")
PRINT a$
' Custom timeout (2 seconds)
LET a$ = SHELL("dir *.txt", 2000)
PRINT a$SLEEP
Pause execution for specified milliseconds.
PRINT "Wait..."
SLEEP 2000
PRINT "Done!"See Also
- Control Flow — IF, FOR, WHILE, GOTO, GOSUB
- Variables & Constants — LET
- Arrays & JSON — DIM
- Comments — REM and ’
Functions
BazzBasic’s built-in functions are organized into separate pages:
- Math Functions — ABS, SIN, COS, LERP, DISTANCE, PI, TAU…
- Fast Trigonometry — FastSin, FastCos, FastRad, lookup tables
- String Functions — LEFT, MID, INSTR, SPLIT, SHA256, BASE64…
- Input Functions — INKEY, KEYDOWN, WAITKEY, MOUSEX/Y…
- Other Functions — RGB, TIME, TICKS
Math Functions
ABS(n)
Returns the absolute value of n.
PRINT ABS(1.5) ' 1.5
PRINT ABS(-1.5) ' 1.5ATAN(n)
Returns the arc tangent of a n
PRINT ATAN(1.5) ' 0.982793723247329
PRINT ATAN(-1.5) ' -0.982793723247329ATAN2(n, n2)
Returns the angle, in radians, between the positive x-axis and a vector to the point with the given (x, y) coordinates in the Cartesian plane.
PRINT ATAN2(5, 10) ' 0.4636476090008061BETWEEN(n, min, max)
Returns true if n is equal or between min and max
BETWEEN(1, 1, 10) ' true
BETWEEN(2, 1, 10) ' true
INBETWEEN(1, 1, 10) ' false
INBETWEEN(2, 1, 10) ' trueUnlike INBETWEEN which returns true if n is not equal and between min and max, BETWEEN returns true if n is equal and between min and max
CINT(n)
The Cint function converts an expression to type Integer.
PRINT CINT(3.7) ' Output: 4
PRINT CINT(3.3) ' Output: 3
PRINT CINT(-3.7) ' Output: -4CEIL(n)
Returns the smallest integer that is greater than or equal to a given number
PRINT CEIL(3.7) ' Output: 4
PRINT CEIL(3.3) ' Output: 4
PRINT CEIL(-3.7) ' Output: -3COS(n)
Returns the cosine of an angle
PRINT COS(0) ' Output: 1
PRINT COS(45) ' Output 0.5253219888177297
PRINT COS(90) ' Output: -0.4480736161291701CLAMP(n, min, max)
If the given parameter n falls below or exceeds the given limit values min or max, it is returned within the limits
LET brightness$ = CLAMP(value$, 20, 255)
' Replaces lines
' IF brightness$ < 20 THEN brightness$ = 20
' IF brightness$ > 255 THEN brightness$ = 255DEG(radians)
Converts radians to degrees.
PRINT DEG(PI#) ' Output: 180
PRINT DEG(HPI#) ' Output: 90
PRINT DEG(2 * PI#) ' Output: 360
' Convert result back to degrees
LET angle_rad$ = 1.5707963267948966
PRINT DEG(angle_rad$) ' Output: 90DISTANCE(x1, y1, x2, y2) or DISTANCE(x1, y1, z1, x2, y2, z2)
Returns the Euclidean distance between two points. Supports both 2D and 3D.
2D mode (4 parameters):
PRINT DISTANCE(0, 0, 3, 4) ' Output: 5 (3-4-5 triangle)
PRINT DISTANCE(10, 20, 40, 60) ' Output: 503D mode (6 parameters):
PRINT DISTANCE(0, 0, 0, 1, 1, 1) ' Output: 1.732... (sqrt of 3)
PRINT DISTANCE(0, 0, 0, 0, 0, 5) ' Output: 5Practical example:
LET playerX$ = 100, playerY$ = 200
LET enemyX$ = 250, enemyY$ = 350
LET dist$ = DISTANCE(playerX$, playerY$, enemyX$, enemyY$)
IF dist$ < 50 THEN
PRINT "Enemy is close!"
END IFEULER
Returns the Euler’s constant, 2.718281828459045
PRINT EULER# ' Output: 2.718281828459045EXP(n)
Exponential (e^n).
PRINT EXP(1) ' Output: 2.718...
PRINT EXP(0) ' Output: 1FLOOR(n)
Rounds down and returns the largest integer
PRINT FLOOR(1.1) ' Output: 1
PRINT FLOOR(1.95) ' Output: 1
PRINT FLOOR(300) ' Output: 300HPI
Returns half of π (pi/2) ≈ 1.5707963267948966. Equivalent to 90 degrees in radians.
Useful in graphics and game programming where 90-degree angles are common.
PRINT HPI# ' Output: 1.5707963267948966
PRINT DEG(HPI#) ' Output: 90
' Common angles in radians using built-in constants
LET angle_0$ = 0 ' 0 degrees
LET angle_45$ = QPI# ' 45 degrees
LET angle_90$ = HPI# ' 90 degrees
LET angle_180$ = PI# ' 180 degrees
LET angle_270$ = PI# + HPI# ' 270 degrees
LET angle_360$ = TAU# ' 360 degreesINBETWEEN(n, min, max)
Returns true, if n is between min and max and not equal to them
INBETWEEN(1, 1, 10) ' false
INBETWEEN(2, 1, 10) ' true
BETWEEN(1, 1, 10) ' true
BETWEEN(2, 1, 10) ' trueUnlike BETWEEN which returns true if n is equal or between min and max, INBETWEEN returns true if n is not equal and between min and max
INT(n)
Returns the integer part (truncates toward zero).
PRINT INT(3.7) ' Output: 3
PRINT INT(-3.7) ' Output: -3LERP(start, end, t)
Linear interpolation between two values. Returns a value between start and end based on parameter t (0.0 to 1.0).
Parameters: - start - Starting value
(when t = 0) - end - Ending value (when t = 1) -
t - Interpolation factor (0.0 to 1.0) -
t = 0.0 returns start - t = 0.5
returns halfway between - t = 1.0 returns end
Formula:
result = start + (end - start) × t
Basic examples:
PRINT LERP(0, 100, 0) ' Output: 0 (0% of the way)
PRINT LERP(0, 100, 0.5) ' Output: 50 (50% of the way)
PRINT LERP(0, 100, 1) ' Output: 100 (100% of the way)
PRINT LERP(10, 20, 0.25) ' Output: 12.5
PRINT LERP(10, 20, 0.75) ' Output: 17.5Practical examples:
Distance-based brightness (raycasting):
LET maxDist# = 10
LET t$ = CLAMP(distance$ / maxDist#, 0, 1)
LET brightness$ = LERP(255, 20, t$) ' Bright nearby, dark far awaySmooth camera movement:
LET t$ = 0.1 ' 10% closer each frame
cameraX$ = LERP(cameraX$, targetX$, t$)
cameraY$ = LERP(cameraY$, targetY$, t$)LOG(n)
Natural logarithm (base e).
PRINT LOG(2.718) ' Output: 0.999896315728952MAX(n, n)
Return higher one from two numbers
LET A# = 1
LET A$ = 9.8
PRINT MAX(A#, A$) ' Output: 9.8MIN(n, n)
Return smaller one from two numbers
LET A# = 1
LET A$ = 9.8
PRINT MIN(A#, A$) ' Output: 1MOD(n, n)
Return modulus (remainder) of the two numbers
PRINT MOD(10, 3) ' Output: 1
PRINT MOD(100, 20) ' Output: 0PI
Returns the mathematical constant π (pi) ≈ 3.14159265358979.
PRINT PI# ' Output: 3.14159265358979
LET circumference$ = 2 * PI# * radius$
LET area$ = PI# * radius$ * radius$POW(n, n)
Return a number raised to the power of another number
PRINT POW(3, 3) ' Output: 27
PRINT POW(2, 2) ' Output: 4QPI
Returns a quarter of π (pi/4) ≈ 0.7853981633974475. Equivalent to 45 degrees in radians.
PRINT QPI# ' Output: 0.7853981633974475
PRINT DEG(QPI#) ' Output: 45
LET dx$ = COS(QPI#) ' ~0.707
LET dy$ = SIN(QPI#) ' ~0.707RAD(degrees)
Converts degrees to radians.
PRINT RAD(90) ' Output: 1.5707963267948966 (HPI#)
PRINT RAD(180) ' Output: 3.141592653589793 (PI#)
PRINT RAD(360) ' Output: 6.283185307179586 (TAU#)
PRINT SIN(RAD(90)) ' Output: 1
PRINT COS(RAD(180)) ' Output: -1RND(n)
Returns a random integer from 0 to n-1 or a floating point between 0 and 1.
PRINT RND(10) ' Output: 0-9
PRINT RND(100) ' Output: 0-99
RND(0) ' Float between 0.0 and 1.0 (IE: 0.5841907423666761)
' Dice roll
LET dice$ = RND(6) + 1ROUND(n)
Rounds a number according to standard rules
PRINT ROUND(1.1) ' Output: 1
PRINT ROUND(1.5) ' Output: 2
PRINT ROUND(1.9) ' Output: 2SGN(n)
Returns the sign: -1, 0, or 1.
PRINT SGN(-5) ' Output: -1
PRINT SGN(0) ' Output: 0
PRINT SGN(5) ' Output: 1SIN(n)
Returns the sine of a number
PRINT SIN(-5) ' Output: 0.9589242746631385
PRINT SIN(0) ' Output: 0
PRINT SIN(5) ' Output: -0.9589242746631385SQR(n)
Returns the square root.
PRINT SQR(0) ' Output: 0
PRINT SQR(5) ' Output: 2.23606797749979
PRINT SQR(9) ' Output: 3TAN(n)
Returns the tangent of the given angle
PRINT TAN(0) ' Output: 0
PRINT TAN(5) ' Output: -3.380515006246586
PRINT TAN(9) ' Output: -0.45231565944180985TAU
Returns τ (tau) = 2π ≈ 6.28318530717958. Equivalent to 360 degrees in radians (a full circle).
PRINT TAU# ' Output: 6.28318530717958
' Full circle loop
FOR angle$ = 0 TO 359
LET rad$ = (angle$ / 360) * TAU#
LET x$ = COS(rad$) * radius$
LET y$ = SIN(rad$) * radius$
NEXT
' All BazzBasic circle constants:
' QPI# = π/4 = 45°
' HPI# = π/2 = 90°
' PI# = π = 180°
' TAU# = 2π = 360°String Functions
ASC(s$)
Returns ASCII code of first character.
PRINT ASC("A") ' Output: 65
PRINT ASC("Hello") ' Output: 72 (H)BASE64DECODE(s$) & BASE64ENCODE(s$)
Decodes and encodes Base64
LET encoded$ = BASE64ENCODE("Hello, World!")
PRINT encoded$ ' SGVsbG8sIFdvcmxkIQ==
LET decoded$ = BASE64DECODE(encoded$)
PRINT decoded$ ' Hello, World!CHR(n)
Returns character for ASCII code.
PRINT CHR(65) ' Output: A
PRINT CHR(10) ' Output: (newline)FSTRING(template$)
String interpolation. Substitutes {{-name-}}
placeholders inside the template with the value of variables, constants,
or array elements. Whitespace inside placeholders is trimmed (so
{{- name$ -}} works the same as {{-name$-}}).
Numbers are auto-converted to strings.
Placeholder forms: - {{-var$-}} —
variable - {{-CONST#-}} — constant -
{{-arr$(0)-}} — array element with numeric index -
{{-arr$(i$)-}} or {{-arr$(KEY#)-}} — array
element where the index comes from a variable / constant (must end in
$ or #) - {{-arr$(name)-}} —
array element with literal string key (matches what was set via
arr$("name") = ...) - {{-arr$(0, i$)-}} —
multidimensional, mixed literal and variable indices
Notes: - No expressions, arithmetic, or function
calls are allowed inside placeholders. Pre-compute into a variable
first. - A bare identifier without $ / #
suffix inside an array index is treated as a literal string key. -
Unknown variable, missing -}}, or empty placeholder halts
execution with a line-numbered error. - The literal sequence
{{-...-}} is reserved — FSTRING will always try to resolve
it.
LET name$ = "Krisu"
LET LEVEL# = 5
PRINT FSTRING("Hello {{-name$-}}, level {{-LEVEL#-}}")
' Output: Hello Krisu, level 5
DIM player$
player$("name") = "Krisu"
player$("level") = 99
PRINT FSTRING("{{-player$(name)-}} is level {{-player$(level)-}}")
' Output: Krisu is level 99
DIM grid$
grid$(0, 0) = "X"
grid$(0, 1) = "O"
LET row$ = 0
PRINT FSTRING("[{{-grid$(row$, 0)-}}{{-grid$(row$, 1)-}}]")
' Output: [XO]INSTR(s$, search$) or INSTR(start, s$, search$)
Finds position of substring (1-based, 0 if not found).
' In default mode, INSTR is case-sensitive
PRINT INSTR("Hello World", "World") ' returns 7
PRINT INSTR("Hello World", "HELLO") ' returns 0
' Case-insensitive mode.
PRINT INSTR("Hello World", "world", 0) ' returns 7
' Case-sensitive mode, same as default mode
PRINT INSTR("Hello World", "world", 1) ' returns 0INVERT(s$)
Inverts a string
PRINT INVERT("Hello World") ' Output: dlroW olleHLCASE(s$)
Converts to lowercase.
PRINT LCASE("Hello") ' Output: helloLEFT(s$, n)
Returns first n characters.
PRINT LEFT("Hello World", 5) ' Output: HelloLEN(s$)
Returns string length.
PRINT LEN("Hello") ' Output: 5
PRINT LEN("") ' Output: 0LTRIM(s$)
Removes blank characters from the left of the text
PRINT LTRIM(" Hello World") ' Output: Hello WorldMID(s$, start) or MID(s$, start, length)
Returns substring starting at position (1-based).
PRINT MID("Hello World", 7) ' Output: World
PRINT MID("Hello World", 7, 3) ' Output: Wor
PRINT MID("Hello World", 1, 5) ' Output: HelloREPEAT(s$, n)
Repeats the text requested times
LET a$ = REPEAT("Foo", 10)
PRINT a$ ' Output: FooFooFooFooFooFooFooFooFooFooREPLACE(s$, a$, b$)
Replaces a$ with b$ from s$
LET text$ = "Hello World"
LET result$ = REPLACE(text$, "World", "BazzBasic")
PRINT result$ ' "Hello BazzBasic"RIGHT(s$, n)
Returns last n characters.
PRINT RIGHT("Hello World", 5) ' Output: WorldRTRIM(s$)
Removes blank characters from the right of the text
LET a$ = "Foo "
LET b$ = "Bar"
a$ = RTRIM(a$)
PRINT a$ + b$ ' Output: FooBarSHA256(s$)
Creates SHA256 hash from a string
LET hash$ = SHA256("password123")
PRINT hash$ ' ef92b778... (64-char lowercase hex)SPLIT(s$, a$, b$)
Splits string into array according to separator
DIM parts$
LET count$ = SPLIT(parts$, "apple,banana,orange", ",")
PRINT "Parts: "; count$
PRINT parts$(0) ' "apple"
PRINT parts$(1) ' "banana"
PRINT parts$(2) ' "orange"SRAND(n)
Returns random string length of n from allowed chars.
Allowed chars:
ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456780_
PRINT SRAND(10) ' Output example: noAR1S-Qw1STR(n)
Converts number to string.
LET s$ = STR(42)
PRINT "Value: " + s$ ' Output: Value: 42TRIM(s$)
Removes blank characters from start and end of text
LET a$ = " Foo "
LET b$ = " Bar "
a$ = TRIM(a$)
b$ = TRIM(b$)
PRINT a$ + b$ ' Output: FooBarUCASE(s$)
Converts to uppercase.
PRINT UCASE("Hello") ' Output: HELLOVAL(s$)
Converts string to number.
LET n$ = VAL("42")
PRINT n$ + 8 ' Output: 50Input Functions
INKEY
Returns current key press (non-blocking). Returns 0 if no key pressed.
[loop]
LET k$ = INKEY
IF k$ = 0 THEN GOTO [loop]
IF k$ = KEY_ESC# THEN END
PRINT "Key code: "; k$
GOTO [loop]Special keys return values > 256: - Arrow keys: KEY_UP#, KEY_DOWN#, KEY_LEFT#, KEY_RIGHT# - Function keys: KEY_F1# through KEY_F12#
KEYDOWN
Read key states via key constants
Note: KEYDOWN availale only when graphics screen used.
Not via console
REM KEYDOWN Test
SCREEN 12
LET x$ = 320
LET y$ = 240
WHILE INKEY <> KEY_ESC#
SCREENLOCK ON
LINE (0,0)-(640,480), 0, BF
IF KEYDOWN(KEY_W#) THEN y$ = y$ - 2
IF KEYDOWN(KEY_S#) THEN y$ = y$ + 2
IF KEYDOWN(KEY_A#) THEN x$ = x$ - 2
IF KEYDOWN(KEY_D#) THEN x$ = x$ + 2
IF KEYDOWN(KEY_LSHIFT#) THEN
CIRCLE (x$, y$), 20, RGB(255, 0, 0), 1
ELSE
CIRCLE (x$, y$), 10, RGB(0, 255, 0), 1
END IF
LOCATE 1, 1
COLOR 15, 0
PRINT "WASD=Move SHIFT=Big ESC=Quit"
LOCATE 2, 1
PRINT "X:"; x$; " Y:"; y$; " "
SCREENLOCK OFF
SLEEP 16
WEND
ENDWAITKEY
Halts execution until one of the specified keys is pressed. Returns the key value.
' Wait for ENTER only
PRINT "Press ENTER to continue"
LET foo$ = WAITKEY(KEY_ENTER#)
' Wait for any of several keys, capture result
PRINT "Press A, B or ESC"
LET k$ = WAITKEY(KEY_A#, KEY_B#, KEY_ESC#)
PRINT "You pressed: "; k$
' Wait for any key
PRINT "Press any key..."
LET k$ = WAITKEY()
PRINT "Key value: "; k$| Feature | INKEY | KEYDOWN | WAITKEY |
|---|---|---|---|
| Blocking | No | No | Yes |
| Returns | Key value or 0 | TRUE/FALSE | Key value |
| Use case | Game loops | Held keys | Menus, pauses |
CURPOS
Returns the current cursor position. Useful for reading where the cursor is after PRINT or LOCATE.
LOCATE 5, 10
PRINT "Hello"
PRINT CURPOS("row") ' Output: 5
PRINT CURPOS("col") ' Output: 15 (10 + 5 chars of "Hello")| Parameter | Returns |
|---|---|
"row" |
Current cursor row (1-based) |
"col" |
Current cursor column (1-based) |
MOUSEX, MOUSEY
Note: Only available when graphics screen is open.
Returns mouse cursor position.
SCREEN 12
[loop]
LOCATE 1, 1
PRINT "X:"; MOUSEX; " Y:"; MOUSEY; " "
GOTO [loop]MOUSELEFT, MOUSERIGHT, MOUSEMIDDLE
Note: Only available when graphics screen is open.
Returns 1 if the specified mouse button is currently pressed, 0 otherwise.
IF MOUSELEFT THEN PRINT "Left clicked"
IF MOUSERIGHT THEN PRINT "Right clicked"
IF MOUSEMIDDLE THEN PRINT "Middle clicked"MOUSEHIDE & MOUSESHOW
In graphics screen, MOUSEHIDE hides the mouse cursor while MOUSESHOW will bring it back.
MOUSEHIDE ' hides mouse
SLEEP 5000
MOUSESHOW ' brings it backFast Trigonometry (Lookup Tables)
For graphics-intensive applications (games, raycasting, animations),
BazzBasic provides fast trigonometric functions using pre-calculated
lookup tables. These are significantly faster than standard
SIN/COS functions but have 1-degree
precision.
Performance: ~20x faster than
SIN(RAD(x)) for integer degree values.
Memory: Uses ~5.6 KB when enabled (360 values × 2 tables × 8 bytes).
FastTrig(enable)
Enables or disables fast trigonometry lookup tables.
Parameters: - TRUE (or any non-zero
value) - Creates lookup tables - FALSE (or 0) - Destroys
lookup tables and frees memory
Important: Must call FastTrig(TRUE)
before using FastSin, FastCos, or
FastRad.
FastTrig(TRUE)
LET x$ = FastCos(45)
LET y$ = FastSin(45)
FastTrig(FALSE)FastSin(angle)
Returns the sine of an angle (in degrees) using a lookup table. Angle is automatically normalized to 0-359. Precision: 1 degree.
FastTrig(TRUE)
PRINT FastSin(0) ' Output: 0
PRINT FastSin(90) ' Output: 1
PRINT FastSin(180) ' Output: 0
PRINT FastSin(270) ' Output: -1
' Angles are automatically wrapped
PRINT FastSin(450) ' Same as FastSin(90) = 1
PRINT FastSin(-90) ' Same as FastSin(270) = -1
FastTrig(FALSE)FastCos(angle)
Returns the cosine of an angle (in degrees) using a lookup table. Angle is automatically normalized to 0-359. Precision: 1 degree.
FastTrig(TRUE)
PRINT FastCos(0) ' Output: 1
PRINT FastCos(90) ' Output: 0
PRINT FastCos(180) ' Output: -1
PRINT FastCos(270) ' Output: 0
FOR angle$ = 0 TO 359
LET dx$ = FastCos(angle$)
LET dy$ = FastSin(angle$)
' Cast ray in direction (dx, dy)
NEXT
FastTrig(FALSE)FastRad(angle)
Converts degrees to radians using an optimized formula. Angle is automatically normalized to 0-359.
Note: Does not require
FastTrig(TRUE).
PRINT FastRad(90) ' Output: 1.5707963267948966 (HPI)
PRINT FastRad(180) ' Output: 3.141592653589793 (PI)
PRINT FastRad(360) ' Output: 6.283185307179586 (2*PI)When to Use Fast Trig
Use FastTrig when: - Rendering graphics at high
frame rates (60+ FPS) - Raycasting or ray tracing - Rotating sprites or
shapes - Particle systems with many particles - Any loop that calls
SIN/COS hundreds of times per frame
Use regular SIN/COS when: - Scientific calculations requiring high precision - One-time calculations - Angles are not in integer degrees
Color Functions
RGB(r, g, b)
Creates a color value from red, green, and blue components (0-255 each).
LET red$ = RGB(255, 0, 0)
LET green$ = RGB(0, 255, 0)
LET blue$ = RGB(0, 0, 255)
LET white$ = RGB(255, 255, 255)
LET black$ = RGB(0, 0, 0)
LET purple$ = RGB(128, 0, 128)
PSET 100, 100, RGB(255, 128, 0) ' Orange pixel
LINE (0, 0)-(100, 100), RGB(0, 255, 0) ' Green line
CIRCLE 200, 200, 50, RGB(255, 0, 0) ' Red circleTip: Store frequently used colors in constants for better performance:
LET COLOR_PLAYER# = RGB(0, 128, 255)
LET COLOR_ENEMY# = RGB(255, 64, 64)
LET COLOR_BG# = RGB(32, 32, 48)Time Functions
TIME(format$)
Returns current date/time as a formatted string. Uses .NET DateTime format strings.
PRINT TIME() ' Default: "16:30:45"
PRINT TIME("HH:mm:ss") ' "16:30:45"
PRINT TIME("dd.MM.yyyy") ' "09.01.2026"
PRINT TIME("yyyy-MM-dd") ' "2026-01-09"
PRINT TIME("dddd") ' "Friday"
PRINT TIME("MMMM") ' "January"
PRINT TIME("dd MMMM yyyy") ' "09 January 2026"
PRINT TIME("HH:mm") ' "16:30"Common format codes: | Code | Description | Example | |——|————-|———| | HH | Hour (00-23) | 16 | | mm | Minutes | 30 | | ss | Seconds | 45 | | dd | Day | 09 | | MM | Month (number) | 01 | | MMM | Month (short) | Jan | | MMMM | Month (full) | January | | yy | Year (2 digits) | 26 | | yyyy | Year (4 digits) | 2026 | | ddd | Weekday (short) | Fri | | dddd | Weekday (full) | Friday |
TICKS
Returns milliseconds elapsed since program started. Useful for timing, animations, and game loops.
LET start$ = TICKS
FOR i$ = 1 TO 10000
LET x$ = x$ + 1
NEXT
LET elapsed$ = TICKS - start$
PRINT "Time taken: "; elapsed$; " ms"Game loop timing example:
SCREEN 12
LET lastFrame$ = TICKS
LET frameTime# = 16 ' ~60 FPS
[gameloop]
LET now$ = TICKS
IF now$ - lastFrame$ >= frameTime# THEN
' Update game logic here
lastFrame$ = now$
END IF
IF INKEY = KEY_ESC# THEN END
GOTO [gameloop]Console Functions
GETCONSOLE(row, col, type)
Reads a character or color from a specific position on the console screen. Console only — not available in graphics mode.
Parameters: - row — row (1-based) -
col — column (1-based) - type — 0 = character
(as ASCII code), 1 = foreground color, 2 = background color
CLS
COLOR 11, 1
PRINT "abcdefghi"
PRINT "ABCDEFGHI"
COLOR 1, 9
PRINT "987654321"
COLOR 15, 0
PRINT "Row 2, col 5 char is: " + CHR(GETCONSOLE(2, 5, 0)) ' Output: E
PRINT "Row 1, col 2 foreground color: " + GETCONSOLE(1, 2, 1) ' Output: 11
PRINT "Row 1, col 3 background color: " + GETCONSOLE(1, 3, 2) ' Output: 1Command Line Arguments
ARGCOUNT
Return the amount of arguments passed to program.
' BazzBasic.exe test.bas arg1 arg2
PRINT ARGCOUNT ' 2ARGS()
Returns certain argument, if passed.
' BazzBasic.exe test.bas arg1 arg2
PRINT ARGS(0)
PRINT ARGS(1)
' Output:
' arg1
' arg2Important
- Always check with ARGCOUNT first, is there arguments passed
- ARGCOUNT gives the amount of arguments but ARGS() places first argument in ARGS(0), not in ARGS(1).
Variable Functions
ISSET(name)
Returns 1 if the named variable
($) or constant (#) is
declared, 0 otherwise. Useful for guarding optional
parameters, checking whether LET has run on a code path, or
branching on configuration values.
ISSET only sees scalar variables and constants. Arrays
and array elements are stored in a separate namespace and always return
0 — use the array-specific functions if you need to check
those.
LET a$ = "hello"
LET b$ ' declared with no value
LET MAX# = 100
PRINT ISSET(a$) ' 1
PRINT ISSET(b$) ' 1 (LET declares it even without a value)
PRINT ISSET(MAX#) ' 1
PRINT ISSET(undef$) ' 0
PRINT ISSET(UNDEF#) ' 0Suffix matters. a$ and A#
are two different names — $ and # are part of
the identifier:
LET a$ = "foo"
PRINT ISSET(a$) ' 1
PRINT ISSET(A#) ' 0 - the constant A# does not existArrays return 0. The array name is not a scalar variable, and array elements are not scalars either:
DIM arr$
arr$(0) = "zero"
PRINT ISSET(arr$) ' 0
PRINT ISSET(arr$(0)) ' 0
PRINT ISSET(arr$(99)) ' 0Typical use — guarding optional setup:
IF NOT ISSET(playerName$) THEN
LET playerName$ = "Anonymous"
END IFImportant
ISSETaccepts only a single bare variable or constant name.ISSET(a$ + b$),ISSET("a$"),ISSET(42), andISSET()are all errors.- The argument is not evaluated —
ISSET(undef$)is safe and returns0, it does not raise an “undefined variable” error.
File handling
BazzBasic includes a simple but powerful file system for reading and writing text files, enabling games to save scores, settings, and game state.
Overview
The file system allows you to: - Read text file contents as strings - Write or overwrite files - Append content to existing files - Check if files exist - Delete files - Work with both relative and absolute paths - Automatically create directories as needed
Supported File Operations
- Text file reading - Load entire file as string
- Text file writing - Create or overwrite files
- Text file appending - Add content to end of files
- File existence checking - Verify files exist before operations
- File deletion - Remove files from disk
- Automatic directory creation - Parent directories created automatically
File Functions
FileRead(filepath$)
Reads the entire contents of a text file and returns it as a string or array.
Returns: String - Complete file contents, or empty string if file doesn’t exist or error occurs
Syntax:
content$ = FileRead("path/to/file.txt")Example with variable:
LET config$
config$ = FileRead("settings.txt")
IF LEN(config$) > 0 THEN
PRINT "Config loaded: "; config$
ELSE
PRINT "Config file not found"
ENDIFExample with array:
LET FILENAME# = "array.txt"
DIM a$
a$("first") = 1
a$("second") = 2
a$("third") = 3
a$("fourth") = "Four"
a$("fourth", "temp") = "Temp"
FileWrite FILENAME#, a$
DIM b$ = FileRead(FILENAME#)
PRINT b$("fourth", "temp")Notes: - Returns empty string on error (no exception thrown) - Handles various text encodings automatically - Best for small to medium-sized text files - Line breaks are preserved in the returned string
FileExists(filepath$)
Checks whether a file exists at the specified path.
Returns: Number - 1 if file exists, 0 if not
Syntax:
LET exists# = FileExists("path/to/file.txt")Example:
IF FileExists("highscore.txt") = 1 THEN
PRINT "Loading existing scores..."
LET scores$ = FileRead("highscore.txt")
ELSE
PRINT "No saved scores found"
LET scores$ = "0"
ENDIFNotes: - Safe to call on any path - Returns 0 if path doesn’t exist or access is denied - Use before FileRead to avoid empty string results - Useful for conditional file operations
File Commands
FileWrite filepath$, content$
Writes content to a file, creating it if it doesn’t exist or overwriting it completely if it does.
Syntax:
FileWrite filepath$, content$Example with string:
LET score$ = 12345
LET playerName$ = "Alice"
LET saveData$ = playerName$ + "\n" + STR(score$)
FileWrite "savegame.txt", saveData$
PRINT "Game saved!"Example with array:
LET FILENAME# = "array.txt"
DIM a$
a$("first") = 1
a$("second") = 2
a$("third") = 3
a$("fourth") = "Four"
a$("fourth", "temp") = "Temp"
FileWrite FILENAME#, a$
DIM b$ = FileRead(FILENAME#)
PRINT b$("fourth", "temp") ' Outputs: TempNotes: - Creates parent directories automatically if
they don’t exist - Completely replaces existing file contents - Silent
operation - no return value - Use \n for line breaks in
content - Escape backslashes in paths: "data\\save.txt" or
use forward slash: "data/save.txt"
FileAppend filepath$, content$
Appends content to the end of an existing file, or creates the file if it doesn’t exist.
Syntax:
FileAppend filepath$, content$Example:
LET timestamp$ = "2025-01-04 15:30:00"
LET logEntry$ = timestamp$ + " - Game started\n"
FileAppend "gamelog.txt", logEntry$Notes: - Creates file if it doesn’t exist - Adds content to end without removing existing data - Perfect for logging and incremental data - Creates directories automatically if needed
FileDelete filepath$
Deletes a file from the file system.
Syntax:
FileDelete filepath$Example:
REM Clean up temporary files
IF FileExists("temp.dat") = 1 THEN
FileDelete "temp.dat"
PRINT "Temporary file removed"
ENDIFNotes: - Silent operation if file doesn’t exist - Irreversible operation - use with caution - Useful for cleanup and reset operations
Loading key=value Files into Arrays (.env support)
When FileRead assigns to a DIM’d array,
BazzBasic automatically parses the file contents line by line into array
elements — using the key=value format that
.env files use.
DIM config$
LET config$ = FileRead("settings.txt")
PRINT config$("width") ' Output: 800
PRINT config$("height") ' Output: 600
PRINT config$("title") ' Output: My GameWhere settings.txt contains:
width=800
height=600
title=My Game
Lines beginning with # are treated as comments and
ignored:
# Game settings
width=800
height=600
# Display options
fullscreen=0
Using .env files for API keys
This makes standard .env files work directly for storing
sensitive values such as API keys outside of source code:
IF FileExists(".env") = 0 THEN
PRINT "Error: .env file not found"
END
END IF
DIM env$
LET env$ = FileRead(".env")
LET ApiKey# = env$("OPENAI_API_KEY")
LET OtherKey# = env$("OTHER_SERVICE_KEY")Where .env contains:
OPENAI_API_KEY=sk-proj-...
OTHER_SERVICE_KEY=abc123...
Important: Add .env to your
.gitignore to keep API keys out of version control:
.env
Note: This parsing only happens when assigning
FileRead to a DIM’d array. Assigning to a
regular variable (LET data$) always returns the raw file
contents as a plain string.
Path Handling
Relative vs Absolute Paths
Relative Paths (recommended for game files):
FileWrite "highscore.txt", "1000" REM Same directory as program
FileWrite "data/settings.txt", "sound=on" REM SubdirectoryAbsolute Paths (for system-wide access):
FileWrite "C:/Users/Player/Documents/save.txt", "data"Note: Use forward slashes / or escaped
backslashes \\ to avoid escape sequence issues:
REM CORRECT:
FileWrite "data/file.txt", "content"
FileWrite "data\\file.txt", "content"
REM WRONG (escape sequences):
FileWrite "data\file.txt", "content" REM \f becomes form feed!PRG_ROOT# Constant
BazzBasic provides a PRG_ROOT# constant containing the
program’s base directory path.
Example:
PRINT "Program root: "; PRG_ROOT#
REM Build absolute paths
LET savePath# = PRG_ROOT# + "/saves/game1.txt"
FileWrite savePath#, "Player data"Use Cases: - Ensuring consistent file locations - Building absolute paths from relative ones - Debugging path issues
Complete Example: Highscore System
REM ============================================
REM Highscore Save/Load System
REM ============================================
CLS
PRINT "=== Highscore Demo ==="
PRINT ""
LET scoreFile$ = "highscore.txt"
LET currentScore$
REM Load existing highscore
IF FileExists(scoreFile$) = 1 THEN
LET scoreData$ = FileRead(scoreFile$)
LET highScore# = VAL(scoreData$)
PRINT "Current highscore: "; highScore$
ELSE
PRINT "No previous highscore found"
ENDIF
PRINT ""
PRINT "Play the game..."
REM Simulate gameplay
currentScore$ = RND(10000)
PRINT "Your score: "; currentScore$
PRINT ""
REM Check if new highscore
IF currentScore$ > highScore# THEN
PRINT "NEW HIGHSCORE!"
FileWrite scoreFile$, STR(currentScore$)
PRINT "Highscore saved!"
ELSE
PRINT "Better luck next time!"
ENDIF
ENDComplete Example: Game Settings
REM ============================================
REM Game Settings Manager
REM ============================================
LET settingsFile$ = "settings.txt"
LET soundEnabled$ = "1"
LET musicVolume$ = "80"
LET difficulty$ = "medium"
REM Load settings if they exist
IF FileExists(settingsFile$) = 1 THEN
PRINT "Loading settings..."
LET settings$ = FileRead(settingsFile$)
REM Parse settings (simple format: one per line)
REM In real game, you'd parse the string
PRINT "Settings loaded"
ELSE
PRINT "Creating default settings..."
REM Build settings string
LET settings$ = ""
settings$ = settings$ + "sound=" + soundEnabled$ + "\n"
settings$ = settings$ + "volume=" + musicVolume$ + "\n"
settings$ = settings$ + "difficulty=" + difficulty$ + "\n"
FileWrite settingsFile$, settings$
PRINT "Default settings saved"
ENDIF
REM Display settings
PRINT ""
PRINT "Current Settings:"
PRINT settings$
ENDComplete Example: Game Event Log
REM ============================================
REM Event Logging System
REM ============================================
LET logFile$ = "gamelog.txt"
REM Initialize log file
IF FileExists(logFile$) = 0 THEN
FileWrite logFile$, "=== Game Log ===\n"
ENDIF
REM Function to log an event
REM (In real code, use DEF FN)
LET event$ = "Game started"
FileAppend logFile$, event$ + "\n"
REM Simulate game events
SLEEP 1000
event$ = "Player spawned at (100, 200)"
FileAppend logFile$, event$ + "\n"
SLEEP 1000
event$ = "Enemy encountered"
FileAppend logFile$, event$ + "\n"
SLEEP 1000
event$ = "Player health: 75"
FileAppend logFile$, event$ + "\n"
SLEEP 1000
event$ = "Game ended"
FileAppend logFile$, event$ + "\n"
PRINT "Events logged!"
PRINT ""
PRINT "Log contents:"
PRINT FileRead(logFile$)
ENDComplete Example: Save Game System
REM ============================================
REM Simple Save Game System
REM ============================================
LET saveFile$ = "savegame.dat"
REM Game state variables
LET playerName$ = "Hero"
LET playerLevel$ = 5
LET playerHealth$ = 85
LET playerGold$ = 1250
LET currentMap$ = "dungeon_2"
REM === SAVE GAME ===
PRINT "Saving game..."
REM Build save data string (simple format)
LET saveData$ = ""
saveData$ = saveData$ + playerName$ + "\n"
saveData$ = saveData$ + STR(playerLevel$) + "\n"
saveData$ = saveData$ + STR(playerHealth$) + "\n"
saveData$ = saveData$ + STR(playerGold$) + "\n"
saveData$ = saveData$ + currentMap$ + "\n"
FileWrite saveFile$, saveData$
PRINT "Game saved!"
PRINT ""
REM === LOAD GAME ===
PRINT "Loading game..."
IF FileExists(saveFile$) = 1 THEN
LET loadedData$ = FileRead(saveFile$)
PRINT "Save file loaded:"
PRINT loadedData$
REM In real game, parse the string and restore variables
PRINT "Game loaded successfully!"
ELSE
PRINT "No save file found!"
ENDIF
ENDTechnical Details
Automatic Directory Creation
- Parent directories are created automatically when writing files
- Example:
FileWrite "saves/slot1/data.txt", "..."createssaves/slot1/if needed - No need to manually create directory structure
Error Handling
- FileRead: Returns empty string on error (no exception)
- FileExists: Returns 0 on error or non-existent file
- FileWrite/FileAppend/FileDelete: Silent failures (no exceptions)
- Check results with FileExists before/after operations if needed
Character Encoding
- Handles UTF-8 and other common text encodings automatically
- String content preserves line breaks and special characters
- Use
\nfor newlines,\tfor tabs in string literals
Path Resolution
- Relative paths: Resolved from program’s base directory (PRG_ROOT#)
- Absolute paths: Used as-is if rooted (e.g.,
C:/...) - Forward slashes
/work on all platforms - Backslashes must be escaped:
\\
Thread Safety
- All file operations are synchronous
- Safe for sequential access
- Avoid concurrent writes to same file
Best Practices
Check File Existence Before Reading
IF FileExists("data.txt") = TRUE THEN LET data$ = FileRead("data.txt") ELSE LET data$ = "" REM Default value ENDIFUse Relative Paths for Game Files
REM Keep game files organized FileWrite "saves/slot1.dat", saveData$ FileWrite "config/settings.txt", config$Structure Your Save Data
REM Use clear format (one value per line) LET data$ = "" data$ = data$ + "PlayerName=" + name$ + "\n" data$ = data$ + "Score=" + STR(score#) + "\n" FileWrite "save.txt", data$Use FileAppend for Logs
REM Accumulate log entries FileAppend "debug.log", "Error occurred\n"Clean Up Temporary Files
REM At program exit IF FileExists("temp.dat") = 1 THEN FileDelete "temp.dat" ENDIFEscape Path Separators
REM CORRECT: FileWrite "data/save.txt", content$ FileWrite "data\\save.txt", content$ REM WRONG: FileWrite "data\save.txt", content$ REM \s might be escape!
Common Patterns
Save/Load Pattern
REM Save
FileWrite "game.sav", gameState$
REM Load
IF FileExists("game.sav") = 1 THEN
gameState$ = FileRead("game.sav")
ENDIFConfig File Pattern
REM Load or create default
IF FileExists("config.txt") = 0 THEN
FileWrite "config.txt", defaultConfig$
ENDIF
config$ = FileRead("config.txt")Incremental Log Pattern
REM Add entries over time
FileAppend "log.txt", timestamp$ + ": " + message$ + "\n"Multiple Save Slots
LET slot$ = 1
LET filename$ = "save" + STR(slot$) + ".dat"
FileWrite filename$, data$Troubleshooting
Problem: FileRead returns empty string - Check file exists with FileExists first - Verify file path is correct (use forward slashes) - Check file isn’t locked by another program - Try absolute path to debug
Problem: FileWrite doesn’t create file - Check path doesn’t contain invalid characters - Verify disk isn’t full or write-protected - Check permissions on target directory
Problem: Escape sequence in path - Use forward
slashes: "data/file.txt" - Or escape backslashes:
"data\\file.txt" - Avoid: \n, \t,
\r in paths
Problem: Can’t find files after writing - Print PRG_ROOT# to see base directory - Use absolute paths for debugging - Check program’s working directory
Limitations
- Text files only (no binary data support)
- No file size limits enforced (use caution with large files)
- No file locking or concurrent access control
- No directory enumeration (can’t list files in folder)
- No file metadata (size, dates, permissions)
- No copy or move operations
Future Enhancements
Potential additions to the file system: - Binary file support (read/write bytes) - Directory listing and enumeration - File copy and move operations - File metadata queries (size, modified date) - File locking for concurrent access - Stream-based reading for large files - CSV and JSON parsing helpers - Compression support
Screen Control
SCREEN - Initialize Graphics Mode
Initialize SDL2 graphics window with specified resolution and title.
SCREEN mode ' Standard BASIC mode
SCREEN 0, width, height ' Custom resolution
SCREEN 0, width, height, "Title" ' Custom resolution with window titleStandard BASIC Modes
| Mode | Resolution | Description |
|---|---|---|
| 0 | 640×400 | Text emulation mode |
| 1 | 320×200 | Low resolution |
| 2 | 640×350 | Medium resolution |
| 7 | 320×200 | VGA low-res |
| 9 | 640×350 | EGA enhanced |
| 12 | 640×480 | VGA standard (recommended) |
| 13 | 320×200 | MCGA mode |
Examples
SCREEN 12 ' 640×480 VGA mode
SCREEN 0, 800, 600 ' 800×600 custom size
SCREEN 0, 1024, 768, "My Game" ' 1024×768 with custom titleCLS
Clear entire screen to background color.
Note: See performance tips for graphics
CLS ' Clear screen
COLOR 0, 1 ' Set blue background
CLS ' Clear to blueFULLSCREEN
Toggle fullscreen mode (borderless window). Note: Fullscreen is only supported in graphics modes (not console mode).
SCREEN 640, 480, "My title"
FULLSCREEN TRUE ' borderless fullscreen on
' ...
FULLSCREEN FALSE ' Windowed modeLOCATE
Move text cursor to specified row and column (1-based).
LOCATE row, column
LOCATE 10, 20 ' Row 10, Column 20
PRINT "Centered"
LOCATE 1, 1 ' Top-left corner
PRINT "Header"Note: - In graphics mode, character positions are based on 8×8 pixel font cells. - While PRINT works, it is recommended to use DRAWSTRING since PRINT can make graphic screen to blink if FPS rate is high.
COLOR
Set foreground (text) and background colors.
COLOR foreground, background
COLOR 14, 1 ' Yellow text on blue background
PRINT "Warning!"
COLOR 15, 0 ' White on black (default)Color Palette (0-15)
| Value | Color | Value | Color |
|---|---|---|---|
| 0 | Black | 8 | Dark Gray |
| 1 | Blue | 9 | Light Blue |
| 2 | Green | 10 | Light Green |
| 3 | Cyan | 11 | Light Cyan |
| 4 | Red | 12 | Light Red |
| 5 | Magenta | 13 | Light Magenta |
| 6 | Brown | 14 | Yellow |
| 7 | Light Gray | 15 | White |
SCREENLOCK
Control when graphics are displayed to prevent flickering.
SCREENLOCK ON ' Lock screen (start buffering)
SCREENLOCK OFF ' Unlock and display (present buffer)
SCREENLOCK ' Same as SCREENLOCK ONWhy use SCREENLOCK? Without screen locking, each graphics command immediately updates the display, causing visible flickering during animation. SCREENLOCK buffers all drawing commands and displays them at once.
Example - Smooth Animation
[inits]
' declarations and initialisations before loops etc.
LET angle$ = 0
SCREEN 12
[main]
WHILE INKEY <> 27
' keep logic and math out of SCREENLOCK ON/OFF
angle$ = angle$ + 5
' Start buffering. Indents helps with SCREENLOCK ON/OFF
SCREENLOCK ON
' clear with LINE...BF
LINE (0, 0)-(640, 480), 0, BF
' Draw multiple shapes
LINE (100,100)-(200,200), 15
CIRCLE (320, 240), 50, 12
SCREENLOCK OFF ' Display all at once
SLEEP 16 ' ~60 FPS
WEND
ENDVSYNC
Control vertical synchronization (VSync) to limit or maximize frame rate.
VSYNC(TRUE) ' Enable VSync (default)
VSYNC(FALSE) ' Disable VSyncParameters: - TRUE or any non-zero
value - Enable VSync - FALSE or 0 - Disable
VSync
What is VSync?
VSync synchronizes frame rendering with your monitor’s refresh rate (typically 60Hz = 60 FPS). This prevents screen tearing (horizontal lines during fast motion) but limits maximum frame rate.
When to use: - VSYNC(TRUE) - Normal
gameplay (smoother, no tearing) - VSYNC(FALSE) -
Benchmarking, performance testing, FPS measurement
Important: - VSync is enabled by
default when you call SCREEN - Call
VSYNC after the SCREEN
command - If rendering takes longer than 16.67ms (1/60s), VSync will
lock to 30 FPS instead of 60 FPS
Performance Impact
' With VSync enabled (default):
' - FPS capped at monitor refresh rate (usually 60)
' - Smooth rendering, no screen tearing
' - If frame takes > 16.67ms → drops to 30 FPS
' With VSync disabled:
' - Unlimited FPS (can exceed 100+ FPS)
' - May show screen tearing
' - Better for performance benchmarkingExample - FPS Testing
' BazzBasic version 1.3
' https://ekbass.github.io/BazzBasic/
[inits]
LET frameCount$ = 0
LET lastTime$ = TICKS
LET frameCount$ = 0
LET currentTime$ = 0
LET fps$
SCREEN 12
VSYNC(FALSE) ' Disable for true FPS measurement
LET MY_COLOR# = RGB(255, 255, 255)
[main]
WHILE INKEY <> KEY_ESC#
' Calculate FPS
frameCount$ = frameCount$ + 1
currentTime$ = TICKS
IF currentTime$ - lastTime$ >= 1000 THEN
fps$ = frameCount$ / ((currentTime$ - lastTime$) / 1000)
frameCount$ = 0
lastTime$ = currentTime$
ENDIF
SCREENLOCK ON
' clear
LINE (0, 0)-(640, 480), 0, BF
' filled circle
CIRCLE (320, 240), 50, 12, 1
' fps
DRAWSTRING "FPS: " + STR(INT(fps$)), 0, 0, MY_COLOR#
SCREENLOCK OFF
WEND
VSYNC(TRUE) ' Restore default before exit
ENDExample - Toggle VSync at Runtime
' BazzBasic version 1.3
' https://ekbass.github.io/BazzBasic/
[inits]
SCREEN 12
LET vSyncStatus$ = TRUE
VSYNC(vSyncStatus$)
LET vColor$ = RGB(255, 255, 255)
LET vString$
LET key$
LET running$ = TRUE
[main]
WHILE running$
IF KEYDOWN(KEY_ESC#) THEN running$ = FALSE
IF KEYDOWN(KEY_SPACE#) THEN
vSyncStatus$ = NOT vSyncStatus$
VSYNC(vSyncStatus$)
' Wait until space is released or it gets buffered and in problems
WHILE KEYDOWN(KEY_SPACE#) : WEND
IF vSyncStatus$ = TRUE THEN
vString$ = "VSync: ON "
ELSE
vString$ = "VSync: OFF "
END IF
END IF
SCREENLOCK ON
LINE (0,0)-(639,479), 0, BF
DRAWSTRING vString$, 0, 16, vColor$
SCREENLOCK OFF
SLEEP 16
WEND
ENDTroubleshooting:
If your game runs at 30 FPS instead of 60 FPS with VSync enabled: 1.
Your rendering takes > 16.67ms per frame 2. VSync forces wait for
next refresh (60 FPS ÷ 2 = 30 FPS) 3. Solutions: - Reduce number of rays
in raycaster - Lower screen resolution - Optimize rendering code - Use
VSYNC(FALSE) to test maximum achievable FPS
Basic Graphics Primitives
PSET - Draw Pixel
Draw a single pixel at coordinates (x, y).
PSET (x, y), color
PSET (100, 100), 15 ' White pixel
PSET (320, 240), 12 ' Red pixel at centerLINE - Draw Lines and Boxes
Draw lines or filled/unfilled rectangles.
LINE (x1, y1)-(x2, y2), color ' Line
LINE (x1, y1)-(x2, y2), color, B ' Box (outline)
LINE (x1, y1)-(x2, y2), color, BF ' Box FilledExamples
LINE (10, 10)-(100, 50), 15 ' White line
LINE (50, 50)-(150, 150), 12, B ' Red box outline
LINE (200, 100)-(300, 200), 9, BF ' Blue filled boxCIRCLE - Draw Circle
Draw circle or filled circle at center point.
CIRCLE (centerX, centerY), radius, color
CIRCLE (centerX, centerY), radius, color, filled
CIRCLE (320, 240), 50, 14 ' Yellow circle outline
CIRCLE (100, 100), 30, 12, 1 ' Red filled circlePAINT - Fill Area
Fill an enclosed area with color (flood fill).
PAINT (x, y), fillColor, borderColor
' Draw and fill a box
LINE (100, 100)-(200, 200), 15, B ' White border
PAINT (150, 150), 12, 15 ' Fill red inside white borderRGB - Create Color Value
Create custom RGB color (0-255 per channel).
LET color$ = RGB(red, green, blue)
LET purple$ = RGB(128, 0, 128)
PSET (100, 100), purple$
LET orange$ = RGB(255, 165, 0)
CIRCLE (320, 240), 50, orange$POINT - Read pixel color from screen
Returns a RGP color value from certain point of the screen.
LET c$ = POINT(100, 100)DRAWSTRING & LOADFONT
Render text directly to the SDL2 graphics surface. Requires
SDL2_ttf.dll in the same directory as the interpreter.
' Default font (Arial, size 20)
DRAWSTRING "Hello!", 100, 200, RGB(255, 255, 255)
' Load alternative font — becomes the new active font
LOADFONT "myfont.ttf", 24
DRAWSTRING "Hello!", 100, 200, RGB(255, 255, 255)
' Reset to default (Arial, size 20)
LOADFONT
DRAWSTRING positions text by its top-left
corner. Prefer it over PRINT in graphics mode —
PRINT bypasses the SDL2 rendering pipeline and causes
flickering at higher frame rates.
Fonts
SDL2_ttf loads any standard .ttf or .otf
font file. BazzBasic defaults to Arial (size 20). To
use a different font, call LOADFONT with a font filename
and point size. The loaded font stays active until you call
LOADFONT again or reset it.
Bundling fonts with your program (recommended)
Copy the .ttf file into the same folder as your
.bas file and reference it by filename:
LOADFONT "PressStart2P.ttf", 16
DRAWSTRING "GAME OVER", 200, 200, RGB(255, 0, 0)
This makes your program portable and not dependent on the fonts installed on the user’s system. Free fonts are widely available — Google Fonts offers hundreds under the OFL open-source licence.
Using Windows system fonts
You can also reference fonts already installed on Windows by full path:
LOADFONT "C:\\Windows\\Fonts\\consola.ttf", 14 ' Consolas (monospace)
LOADFONT "C:\\Windows\\Fonts\\times.ttf", 18 ' Times New Roman
Note: this works only on Windows and only if the font is installed — not recommended for distributed programs.
Font sizes
The size parameter is a point size — any positive integer is valid:
| Use | Size |
|---|---|
| Small UI / HUD text | 12–14 |
| Normal text | 16–20 |
| Subheadings | 24–32 |
| Titles / headings | 48–64 |
| Splash screens | 72–96 |
Shape System (Sprites)
LOADSHAPE - Create Shape
Create or load a new shape and return its ID.
id$ = LOADSHAPE(type$, width, height, color)Shape types: - "RECTANGLE" - Rectangle
shape - "CIRCLE" - Circle shape
- "TRIANGLE" - Triangle shape
Examples
LET SQUARE# = LOADSHAPE("RECTANGLE", 50, 50, RGB(255, 0, 0))
LET BALL# = LOADSHAPE("CIRCLE", 40, 40, RGB(0, 255, 0))
LET ARROW# = LOADSHAPE("TRIANGLE", 30, 40, RGB(0, 0, 255))LOADSHEET - Load Sprite Sheet
Reads an image file and splits it into sprites according to the specification. The original image size must be divisible by the given size parameters
' BazzBasic version 1.3
' https://ekbass.github.io/BazzBasic/
' ============================================
' LOADSHEET demo: countdown 9 -> 0
' sheet_numbers.png: 640x256, 128x128 sprites
' ============================================
[inits]
' Center position for a 128x128 sprite on 640x480 screen
LET x# = 256
LET y# = 176
DIM sprites$
SCREEN 0, 640, 480, "Countdown!"
LOADSHEET sprites$, 128, 128, "Examples/images/sheet_numbers.png"
[main]
' Count down from 9 to 0
FOR i$ = ROWCOUNT(sprites$()) - 1 TO 0 STEP -1
SCREENLOCK ON
LINE (0, 0)-(640, 480), 0, BF
MOVESHAPE sprites$(i$), x#, y#
DRAWSHAPE sprites$(i$)
SCREENLOCK OFF
SLEEP 500
NEXT
ENDMOVESHAPE - Position Shape
Move shape to absolute screen position.
MOVESHAPE ID#, x, yROTATESHAPE - Rotate Shape
Rotate shape to specified angle in degrees.
ROTATESHAPE id$, angle
ROTATESHAPE SQUARE#, 45 ' 45 degrees
ROTATESHAPE ARROW#, 180 ' Upside down
ROTATESHAPE ARROW#, 270 ' 90 degrees counter-clockwiseNote: Rotation is absolute, not cumulative. To spin continuously:
DIM angle$
LET angle$ = 0
WHILE 1
angle$ = angle$ + 5
IF angle$ >= 360 THEN
angle$ = 0
ENDIF
ROTATESHAPE SQUARE#, angle$
SLEEP 16
WENDSCALESHAPE - Scale Shape Size
Scale shape by multiplier (1.0 = original size).
SCALESHAPE id$, scale
SCALESHAPE BALL#, 0.5 ' Half size
SCALESHAPE SQUARE#, 2.0 ' Double size
SCALESHAPE ARROW#, 1.5 ' 150% sizePulsing effect:
DIM scale$
DIM direction$
LET scale$ = 1
LET direction$ = 0.01
WHILE 1
scale$ = scale$ + direction$
IF scale$ >= 1.5 OR scale$ <= 0.5 THEN
direction$ = direction$ * -1
ENDIF
SCALESHAPE BALL#, scale$
SLEEP 16
WENDDRAWSHAPE - Render Shape
Draw shape to screen at current position/rotation/scale.
DRAWSHAPE SQUARE#
SCREENLOCK ON
LINE (0, 0)-(640, 480), 0, BF
DRAWSHAPE SQUARE#
DRAWSHAPE BALL#
DRAWSHAPE ARROW#
SCREENLOCK OFFImportant: Use with SCREENLOCK for smooth rendering!
SHOWSHAPE / HIDESHAPE - Toggle Visibility
Show or hide shape without removing it.
SHOWSHAPE id$
HIDESHAPE id$
HIDESHAPE ENEMY# ' Temporarily hide
' ... do something ...
SHOWSHAPE ENEMY# ' Show againREMOVESHAPE - Delete Shape
Permanently remove shape from memory.
REMOVESHAPE ID#
REMOVESHAPE SQUARE# ' Delete and free memoryNote: Always remove shapes when done to free memory!
LOADIMAGE
Note: Images can be handled just as shapes
[inits]
LET SPRITE# = LOADIMAGE("temp.bmp")
SCREEN 12
MOVESHAPE SPRITE#, 320, 240
ROTATESHAPE SPRITE#, 45 ' Rotate 45
SCALESHAPE SPRITE#, 2.0 ' Scale by 2
[main]
SCREENLOCK ON
DRAWSHAPE SPRITE#
SCREENLOCK OFF
SLEEP 3000
REMOVESHAPE SPRITE# ' Free mem
ENDLOADIMAGE with url
LET SPRITE# = LOADIMAGE("https://example.com/sprite.png")
' → downloads "sprite.png" to root of your program
' → sprite$ works just as with normal file load
' to remove or move the downloaded file
SHELL("move sprite.png images\sprite.png") ' move to subfolder
' or
FILEDELETE "sprite.png" ' just delete itDrawing on Screen
Complete Examples
Example 1: Rotating Shapes
Example 2: Bouncing Ball
Performance Tips
Always use SCREENLOCK for animation:
WHILE 1 ' Math and logic here SCREENLOCK ON ' All drawing here SCREENLOCK OFF ' Delay here SLEEP 16 WENDClear only what you need:
' Clear only draw area, not text COLOR 0, 0 LINE (0, 50)-(640, 480), 0, BFLINE… BF is much faster than CLS
' Filling screen with LINE... BF is faster than CLS ' CLS works fine with console COLOR 0, 0 LINE (0, 80)-(640, 480), 0, BFRemove unused shapes:
REMOVESHAPE OLD_SHAPE# ' Free memoryUse RGB() once, store value:
LET MY_COLOR# = RGB(128, 64, 200) ' Use MY_COLOR# multiple timesTarget 60 FPS with SLEEP 16:
SLEEP 16 ' ~60 FPS (1000ms / 60 ≈ 16ms)
Image Support
LOADIMAGE Function
Load images as shapes that can be moved, rotated, and scaled.
Supported Formats
| Format | Transparency | Notes |
|---|---|---|
| PNG | Full alpha (0-255) | Recommended for sprites |
| BMP | None | Legacy support |
Usage
LET ID# = LOADIMAGE("filepath")Parameters: - filepath - Path to image
file (PNG or BMP)
Returns: - Shape ID string (use with MOVESHAPE, ROTATESHAPE, etc.)
Example
[inits]
SCREEN 12
REM Load PNG image with transparency
LET SPRITE# = LOADIMAGE("player.png")
REM Position and transform
MOVESHAPE SPRITE#, 320, 240
ROTATESHAPE SPRITE#, 45
SCALESHAPE SPRITE#, 2.0
[main]
REM Draw
SCREENLOCK ON
DRAWSHAPE SPRITE#
SCREENLOCK OFF
SLEEP 3000
REM Cleanup when done
REMOVESHAPE SPRITE#
ENDPNG Transparency (Alpha Channel)
PNG images support full alpha transparency. Each pixel can have an alpha value from 0 to 255:
| Alpha Value | Result |
|---|---|
| 255 | Fully opaque (solid) |
| 128 | 50% transparent |
| 0 | Fully transparent |
Transparency is read directly from the PNG file - no color key needed.
Image Transformations
Once loaded, images work exactly like other shapes:
LET IMG# = LOADIMAGE("logo.png")
MOVESHAPE IMG#, x, y ' Position (center point)
ROTATESHAPE IMG#, angle ' Rotate (degrees)
SCALESHAPE IMG#, scale ' Scale (1.0 = original size)
SHOWSHAPE IMG# ' Make visible
HIDESHAPE IMG# ' Make invisible
DRAWSHAPE IMG# ' Render to screen
REMOVESHAPE IMG# ' Delete and free memoryNotes
- Images are positioned by their top-left point
- PNG is recommended for all new projects
- Larger images use more memory
Why Constants, Not Variables?
Sound IDs returned by LOADIMAGE and are handles assigned
by SDL2. BazzBasic uses them only to point to the correct image resource
— they never change during program execution.
Storing them in constants (# suffix) communicates this
intent clearly:
LET PISTOL# = LOADIMAGE("pistol.png")
LET GAME_OVER# = LOADIMAGE("gameOver.png")
Using a mutable variable ($ suffix) would work, but it
implies the value could change — which is misleading and leaves
the door open for accidental reassignment bugs.
The rule of thumb: if a value is set once and never modified, it belongs in a constant.
When to Use an Array Instead
If your program loads many images at once, individual constants become verbose. In that case, a named array is cleaner and self-documenting:
DIM images$
images$("shoot") = LOADIMAGE("shoot.png")
images$("explosion") = LOADIMAGE("explosion.png")
images$("pickup") = LOADIMAGE("pickup.png")
For larger projects with categorized images, multidimensional string keys scale even better:
DIM images$
images$("weapons", "shotgun") = LOADIMAGE("shotgun.png")
images$("weapons", "ak47") = LOADIMAGE("ak47.png")
images$("explosions", "small") = LOADIMAGE("explosion_small.png")
images$("explosions", "large") = LOADIMAGE("explosion_large.png")
This keeps image assets organized by category and type — easy to extend without renaming anything.
Sound System
BazzBasic includes a comprehensive sound system built on SDL2_mixer, supporting audio playback with both background and blocking modes.
Overview
The sound system allows you to: - Load sound files in various formats (WAV, MP3, etc.) - Play sounds once or in a continuous loop - Control playback (stop individual sounds or all at once) - Choose between background playback or wait-for-completion modes
Supported Audio Formats
- WAV (recommended for best compatibility)
- MP3
- Other formats supported by SDL2_mixer.dll
Sound Commands
LOADSOUND(filepath$)
Loads a sound file from disk and returns a unique sound ID string.
Returns: String - Unique identifier for the loaded sound
Syntax:
LET SOUND_ID# = LOADSOUND("path/to/sound.wav")
' or
LET SOUND_ID# = LOADSOUND("path\\to\\sound.wav")Note: If you use “", you must use it as double”\” since it is also a escape character
Example:
LET EXPLOSION#
EXPLOSION# = LOADSOUND("C:\\sounds\\explosion.wav")
PRINT "Sound loaded with ID: "; EXPLOSION#Notes: - The file must exist or an error will occur - Each call to LOADSOUND creates a new independent sound instance - The same file can be loaded multiple times for overlapping playback
SOUNDONCE(SOUND_ID#)
Plays a loaded sound once in the background. Program execution continues immediately.
Syntax:
SOUNDONCE(SOUND_ID#)Example:
LET BEEP#
BEEP# = LOADSOUND("beep.wav")
SOUNDONCE(BEEP#)
PRINT "Sound playing in background..."
SLEEP 1000
PRINT "Continuing while sound plays..."Use Cases: - Sound effects in games - UI feedback sounds - Background audio that shouldn’t block program flow
SOUNDONCEWAIT(SOUND_ID#)
Plays a sound once and waits for playback to complete before continuing program execution.
Syntax:
SOUNDONCEWAIT(SOUND_ID#)Example:
LET INTRO#
INTRO# = LOADSOUND("intro_music.wav")
PRINT "Playing intro..."
SOUNDONCEWAIT(INTRO#)
PRINT "Intro finished, starting game!"Use Cases: - Intro music or narration - Sequential audio playback - When timing with program flow is critical
SOUNDREPEAT(SOUND_ID#)
Plays a sound in a continuous loop in the background.
Syntax:
SOUNDREPEAT(SOUND_ID#)Example:
LET BG_MUSIC#
BG_MUSIC# = LOADSOUND("background_music.wav")
SOUNDREPEAT(BG_MUSIC#)
PRINT "Music looping in background..."
REM Game loop runs hereNotes: - Sound loops seamlessly when it reaches the end - Use SOUNDSTOP to stop the loop - Multiple sounds can be looping simultaneously
Use Cases: - Background music - Ambient sounds (rain, wind, etc.) - Continuous sound effects
SOUNDSTOP(SOUND_ID#)
Stops playback of a specific sound.
Syntax:
SOUNDSTOP(SOUND_ID#)Example:
LET ALARM#
ALARM# = LOADSOUND("alarm.wav")
SOUNDREPEAT(ALARM#)
PRINT "Alarm ringing..."
SLEEP 5000
SOUNDSTOP(ALARM#)
PRINT "Alarm stopped"Notes: - Safe to call even if sound is not currently playing - Stops both looping and one-time playback
SOUNDSTOPALL
Stops all currently playing sounds at once.
Syntax:
SOUNDSTOPALLExample:
REM Emergency stop all audio
SOUNDSTOPALL
PRINT "All sounds stopped"Use Cases: - Game pause functionality - Switching between game states - Emergency audio cutoff - Cleanup before program exit
Complete Example: Game with Sound
REM ============================================
REM Simple Game with Sound Effects
REM ============================================
CLS
PRINT "Loading sounds..."
REM Load all game sounds
LET JUMP#, COIN#, DEATH#, BG_MUSIC#
JUMP# = LOADSOUND("C:\\game_sounds\\jump.wav")
COIN# = LOADSOUND("C:\\game_sounds\\coin.wav")
DEATH# = LOADSOUND("C:\\game_sounds\\death.wav")
BG_MUSIC# = LOADSOUND("C:\\game_sounds\\music.wav")
REM Start background music
SOUNDREPEAT(BG_MUSIC#)
REM Game variables
LET score$ = 0
LET playing$ = 1
LET coins_collected$ = 0
PRINT "Game started! Press SPACE to jump, ESC to quit"
REM Main game loop
WHILE playing$
LET key$ = INKEY
IF key$ = KEY_ESC# THEN
playing$ = 0
ENDIF
IF key$ = KEY_SPACE# THEN
SOUNDONCE(JUMP#)
PRINT "Jump!"
ENDIF
REM Simulate collecting a coin
IF RND(100) < 1 THEN
coins_collected$ = coins_collected$ + 1
score$ = score$ + 10
SOUNDONCE(COIN#)
PRINT "Coin collected! Score: "; score$
ENDIF
REM Simulate game over condition
IF coins_collected$ >= 10 THEN
playing$ = 0
ENDIF
SLEEP 50
WEND
REM Game over sequence
SOUNDSTOPALL
PRINT ""
PRINT "Game Over!"
PRINT "Final Score: "; score$
SOUNDONCEWAIT(DEATH#)
PRINT "Thanks for playing!"
ENDExample: Multiple Background Sounds
REM Layer multiple ambient sounds
LET RAIN#, WIND#, THUNDER#
RAIN# = LOADSOUND("rain.wav")
WIND# = LOADSOUND("wind.wav")
THUNDER# = LOADSOUND("thunder.wav")
REM Start ambient background
SOUNDREPEAT(RAIN#)
SOUNDREPEAT(WIND#)
PRINT "Storm ambience playing..."
SLEEP 5000
REM Add thunder effect
SOUNDONCE(THUNDER#)
SLEEP 3000
REM Stop all ambience
SOUNDSTOPALL
PRINT "Storm ended"
ENDExample: Sequential Audio Narration
REM Play audio files in sequence
LET PART1#, PART2#, PART3#
PART1# = LOADSOUND("narration_part1.wav")
PART2# = LOADSOUND("narration_part2.wav")
PART3# = LOADSOUND("narration_part3.wav")
PRINT "Starting narration..."
SOUNDONCEWAIT(PART1#)
PRINT "Part 1 complete"
SOUNDONCEWAIT(PART2#)
PRINT "Part 2 complete"
SOUNDONCEWAIT(PART3#)
PRINT "Narration finished!"
ENDTechnical Details
Thread Safety
- All sound operations are thread-safe
- Multiple sounds can play simultaneously
- Concurrent calls to SOUNDSTOP/SOUNDSTOPALL are handled safely
Memory Management
- Sound files are loaded into memory when LOADSOUND is called
- Each sound instance maintains its own playback state
- Resources are automatically cleaned up when program ends
- Use SOUNDSTOPALL before exit for clean shutdown
Performance Considerations
- Load sounds once at program start for best performance
- Avoid loading the same file repeatedly if possible
- Short sound effects are ideal for SOUNDONCE
- Longer audio files work well with SOUNDREPEAT
Looping Behavior
- SOUNDREPEAT loops seamlessly without gaps
- Loop restarts automatically when sound completes
- IsRepeating flag can be interrupted by SOUNDSTOP
Error Handling
- Invalid file paths throw exceptions with clear error messages
- Missing sound files are reported at load time
- Stopping non-existent sounds is a silent no-op
Best Practices
Organize Your Sounds
REM Load all sounds at startup LET SFX_JUMP#, SFX_COIN#, MUSIC_BG# SFX_JUMP# = LOADSOUND("sfx\\jump.wav") SFX_COIN# = LOADSOUND("sfx\\coin.wav") MUSIC_BG# = LOADSOUND("music\\background.wav")Use Appropriate Playback Modes
SOUNDONCE- Short sound effectsSOUNDREPEAT- Background music, ambient loopsSOUNDONCEWAIT- Sequential audio, narration
Clean Up Audio
REM Before program exit SOUNDSTOPALL ENDHandle Game States
REM When pausing game SOUNDSTOPALL REM When resuming SOUNDREPEAT(BG_MUSIC#)
Why Constants, Not Variables?
Sound IDs returned by LOADSOUND are handles assigned by
SDL2. BazzBasic uses them only to point to the correct audio resource —
they never change during program execution.
Storing them in constants (# suffix) communicates this
intent clearly:
LET SHOOT_SND# = LOADSOUND("shoot.wav")
Using a mutable variable ($ suffix) would work, but it
implies the value could change — which is misleading and leaves
the door open for accidental reassignment bugs.
The rule of thumb: if a value is set once and never modified, it belongs in a constant.
When to Use an Array Instead
If your program loads many sounds at once, individual constants become verbose. In that case, a named array is cleaner and self-documenting:
DIM sounds$
sounds$("shoot") = LOADSOUND("shoot.wav")
sounds$("explosion") = LOADSOUND("explosion.wav")
sounds$("pickup") = LOADSOUND("pickup.wav")
SOUNDOCE(sounds$("shoot"))
For larger projects with categorized sounds, multidimensional string keys scale even better:
DIM sounds$
sounds$("shoot", "shotgun") = LOADSOUND("shoot_shotgun.wav")
sounds$("shoot", "ak47") = LOADSOUND("shoot_ak47.wav")
sounds$("explosion", "small") = LOADSOUND("explosion_small.wav")
sounds$("explosion", "large") = LOADSOUND("explosion_large.wav")
SOUNDONCE(sounds$("shoot", "ak47"))
This keeps sound assets organized by category and type — easy to extend without renaming anything.
Network
Note: httpbin.org is a good test address — it returns JSON showing what you sent. HTTPPOST sends Content-Type: application/json by default.
HTTPGET
Allows you to send HTTP GET requests to a specified URL and retrieve the response as a string.
LET response$ = HTTPGET("https://httpbin.org/get")
PRINT response$Output:
{
"args": {},
"headers": {
"Host": "httpbin.org",
"X-Amzn-Trace-Id": "Root=1-6999cff3-34d8f03c0661810224fe62db"
},
"origin": "84.231.65.52",
"url": "https://httpbin.org/get"
}
HTTPPOST
Allows you to send HTTP POST requests to a specified URL and retrieve the response as a string.
LET postResult$ = HTTPPOST("https://httpbin.org/post", "{""key"":""value""}")
PRINT postResult$Output;
{
"args": {},
"data": "{\"key\":\"value\"}",
"files": {},
"form": {},
"headers": {
"Content-Length": "15",
"Content-Type": "application/json; charset=utf-8",
"Host": "httpbin.org",
"X-Amzn-Trace-Id": "Root=1-6999d03a-3b47996d66ac7d8e65200a1e"
},
"json": {
"key": "value"
},
"origin": "84.231.65.52",
"url": "https://httpbin.org/post"
}
HTTP Server (LISTEN)
BazzBasic can act as a small local HTTP server to receive POST
requests from a browser-side HTML page or other tooling. The intended
use is local-only glue: a static HTML page on the
user’s machine talks to BazzBasic via fetch().
The server is bound to 127.0.0.1 only — no admin rights
are needed on Windows, and the listener is never exposed to the
network.
Commands
| Command | Description |
|---|---|
STARTLISTEN port |
Open the given port. GETREQUEST() will block forever
until a request arrives. |
STARTLISTEN port, timeout_ms |
Same, but GETREQUEST() returns an empty string if no
request arrives within the timeout. |
GETREQUEST() |
Block until a request arrives, then return the
POST/PUT/PATCH body or the GET query
string (without the leading ?). Returns
"" on timeout. |
SENDRESPONSE str$ |
Send 200 OK with the given body,
Content-Type: text/plain; charset=utf-8, and CORS headers.
Must be called after each GETREQUEST() so the browser does
not hang. |
STOPLISTEN |
Close the port. Silent no-op if no listener is active. |
Behaviour
- Only one listener can be active at a time. Calling
STARTLISTENwhile a listener is already open is an error — callSTOPLISTENfirst. OPTIONSpreflight requests sent by browsers for CORS are answered automatically with200 OK+ CORS headers and never reach user code. The script keeps waiting inGETREQUEST()for the real request.- If you call
GETREQUEST()again without first callingSENDRESPONSE, the previous request is automatically closed with an empty200 OKso the browser does not hang. This makes the API forgiving but you should still callSENDRESPONSEexplicitly. - All responses include
Access-Control-Allow-Origin: *, so an HTML page loaded withfile://or from a different port can post to your script without any extra setup.
Example: receive a JSON form post
STARTLISTEN 8080
PRINT "Listening on http://127.0.0.1:8080 ..."
LET json$ = GETREQUEST()
PRINT "Received: " + json$
' Parse the JSON into an array
DIM data$
LET data$ = ASARRAY(json$)
PRINT "Name: " + data$("name")
SENDRESPONSE "{""status"":""ok""}"
STOPLISTEN
ENDMatching browser-side JavaScript:
fetch("http://127.0.0.1:8080", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ name: "Krisu", level: 99 })
})
.then(r => r.json())
.then(data => console.log(data));Example: poll loop with timeout
STARTLISTEN 8080, 2000
LET running$ = 1
WHILE running$
LET req$ = GETREQUEST()
IF LEN(req$) = 0 THEN
PRINT "Idle..."
ELSE
PRINT "Got: " + req$
SENDRESPONSE "ok"
IF req$ = "quit" THEN
LET running$ = 0
END IF
END IF
WEND
STOPLISTEN
ENDNotes & limitations
- Only one request is handled at a time, sequentially. This is intentional — BazzBasic is single-threaded and aims for simple local glue, not high-traffic web serving.
- The response is always
200 OKwithtext/plaincontent type. If you need to return JSON, just put JSON text in the body — browsers can still parse it withresponse.json(). Custom status codes are not supported in this version. GETrequests give you the query string (e.g.name=Krisu&age=50), not the URL path. Routing by path is not supported in this version.- For outgoing HTTP calls (calling other servers), see
HTTPGETandHTTPPOSTabove.
Preprocessor & Source Control
BazzBasic supports splitting your program across multiple files. This helps keep large programs organized and allows reusable code libraries.
INCLUDE
Include another BazzBasic source file. The contents of the included file are inserted at the exact point of the INCLUDE statement — as if you had written the code there directly.
INCLUDE "utils.bas"
INCLUDE "graphics_helpers.bas"
INCLUDE "MathLib.bb" ' Compiled libraryUsage Notes
- Path is relative to the main program file
- Included files can contain functions, constants, or any valid BazzBasic code
- Avoid circular includes (A includes B which includes A)
Example
main.bas:
INCLUDE "helpers.bas"
LET result$ = FN Square$(5)
PRINT result$ ' Output: 25helpers.bas:
DEF FN Square$(n$)
RETURN n$ * n$
END DEFBazzBasic reads these as a single program:
DEF FN Square$(n$)
RETURN n$ * n$
END DEF
LET result$ = FN Square$(5)
PRINT result$ ' Output: 25Compiled Libraries (.bb)
Library files contain only DEF FN functions and are
compiled to a tokenized .bb format.
' Compile: bazzbasic.exe -lib MathLib.bas → MathLib.bb
INCLUDE "MathLib.bb"
' Library functions are prefixed with FILENAME_
PRINT FN MATHLIB_Square$(5) ' Output: 25- Libraries can only contain
DEF FNfunctions - Functions are auto-prefixed with the filename:
MATHLIB_functionname$ - Library functions can read global constants (
#) from the main program .bbfiles are version-locked — may not work across BazzBasic versions
Recommended Program Structure
For larger programs, split code into focused files and INCLUDE them:
' main.bas
INCLUDE "constants.bas"
INCLUDE "functions.bas"
INCLUDE "inits.bas"
[main]
GOSUB [sub:update]
GOSUB [sub:draw]
SLEEP 16
GOTO [main]
END
INCLUDE "subs.bas"See Also
BazzBasic Reserved Words
Complete list of all reserved keywords. All are
case-insensitive.
Variables must end with $, constants with # —
they cannot share names with keywords.
Control Flow
| Keyword | Description |
|---|---|
DEF |
Begin function definition (DEF FN name$(...)) |
DIM |
Declare array |
ELSE |
Alternative branch in IF block |
ELSEIF |
Chained condition in IF block |
END |
Terminate program; also END IF,
END DEF |
ENDIF |
Close IF block (alias for END IF) |
FN |
Call user-defined function (FN name$(...)) |
FOR |
Begin counted loop |
GOSUB |
Call subroutine at label |
GOTO |
Jump to label |
IF |
Conditional branch |
INCLUDE |
Insert source file or library |
LET |
Declare variable or constant |
NEXT |
End FOR loop |
PRINT |
Output to screen |
REM |
Comment (also ') |
RETURN |
Return from GOSUB or DEF FN |
STEP |
Loop increment in FOR |
THEN |
Required after IF condition |
TO |
Range separator in FOR |
WEND |
End WHILE loop |
WHILE |
Begin conditional loop |
I/O
| Keyword | Description |
|---|---|
ARGCOUNT |
Returns amount or args. passed to program |
ARGS |
Returns specific arg. passed to program |
CLS |
Clear screen |
COLOR |
Set text foreground/background color |
CURPOS |
Read cursor row or col: CURPOS("row") /
CURPOS("col") |
GETCONSOLE |
Read character or color from console position |
INPUT |
Read user input |
LINE INPUT |
Read full line including spaces |
LOCATE |
Move text cursor |
SLEEP |
Pause execution (milliseconds) |
Graphics
| Keyword | Description |
|---|---|
CIRCLE |
Draw circle or filled circle |
DRAWSHAPE |
Render a shape/image to screen |
DRAWSTRING |
Render a text to screen |
FULLSCREEN |
Toggle borderless fullscreen |
HIDESHAPE |
Hide shape without removing |
LINE |
Draw line, box outline, or filled box |
LOADFONT |
Load font from file or reset to Arial |
LOADIMAGE |
Load PNG/BMP (or URL) as shape |
LOADSHEET |
Load sprite sheet into array |
LOADSHAPE |
Create geometric shape |
MOVESHAPE |
Set shape position |
PAINT |
Flood fill |
POINT |
Read pixel color |
PSET |
Draw single pixel |
REMOVESHAPE |
Delete shape and free memory |
RGB |
Create color value from R, G, B components |
ROTATESHAPE |
Rotate shape (absolute degrees) |
SCALESHAPE |
Scale shape |
SCREEN |
Initialize graphics window |
SCREENLOCK |
Buffer drawing (ON) / present frame
(OFF) |
SHOWSHAPE |
Make hidden shape visible |
VSYNC |
Enable/disable vertical sync |
Sound
| Keyword | Description |
|---|---|
LOADSOUND |
Load sound file, returns ID |
SOUNDONCE |
Play sound once (non-blocking) |
SOUNDONCEWAIT |
Play sound once (blocking) |
SOUNDREPEAT |
Loop sound continuously |
SOUNDSTOP |
Stop specific sound |
SOUNDSTOPALL |
Stop all sounds |
File
| Keyword | Description |
|---|---|
FILEAPPEND |
Append string to file |
FILEDELETE |
Delete a file |
FILEEXISTS |
Returns 1 if file exists |
FILEREAD |
Read file as string or key=value array |
FILEWRITE |
Write string or array to file |
SHELL |
Run system command, returns output |
Network & Data
| Keyword | Description |
|---|---|
ASARRAY |
Parse JSON string into array |
ASJSON |
Convert array to JSON string |
BASE64DECODE |
Decode Base64 string |
BASE64ENCODE |
Encode string to Base64 |
HTTPGET |
HTTP GET request |
HTTPPOST |
HTTP POST request |
LOADJSON |
Load JSON file into array |
SAVEJSON |
Save array as JSON file |
SHA256 |
SHA256 hash (64-char hex) |
Math Functions
| Keyword | Description |
|---|---|
ABS |
Absolute value |
ATAN |
Arc tangent |
BETWEEN |
TRUE if value is within range |
CEIL |
Round up |
CINT |
Round to nearest integer |
CLAMP |
Constrain value to range |
COS |
Cosine (radians) |
DEG |
Radians to degrees |
DISTANCE |
2D or 3D Euclidean distance |
EULER |
Euler’s number (e = 2.71828…) |
EXP |
e raised to power |
FASTCOS |
Fast cosine (degrees, lookup table) |
FASTRAD |
Fast degrees-to-radians |
FASTSIN |
Fast sine (degrees, lookup table) |
FASTTRIG |
Enable/disable fast trig lookup tables |
FLOOR |
Round down |
HPI |
π/2 (90°) |
INT |
Truncate toward zero |
LERP |
Linear interpolation |
LOG |
Natural logarithm |
MAX |
Higher of two values |
MIN |
Lower of two values |
MOD |
Remainder |
PI |
π (3.14159…) |
POW |
Power |
QPI |
π/4 (45°) |
RAD |
Degrees to radians |
RND |
Random integer 0 to n-1 |
ROUND |
Standard rounding |
SGN |
Sign (-1, 0, 1) |
SIN |
Sine (radians) |
SQR |
Square root |
TAN |
Tangent (radians) |
TAU |
2π (360°) |
String Functions
| Keyword | Description |
|---|---|
ASC |
Character to ASCII code |
CHR |
ASCII code to character |
INSTR |
Find substring position |
INVERT |
Reverse string |
LCASE |
Convert to lowercase |
LEFT |
First n characters |
LEN |
String length (also array element count) |
LTRIM |
Strip leading whitespace |
MID |
Substring |
REPEAT |
Repeat string n times |
REPLACE |
Replace all occurrences |
RIGHT |
Last n characters |
RTRIM |
Strip trailing whitespace |
SPLIT |
Split string into array |
SRAND |
Random alphanumeric string |
STR |
Number to string |
TRIM |
Strip leading and trailing whitespace |
UCASE |
Convert to uppercase |
VAL |
String to number |
Input & Mouse
| Keyword | Description |
|---|---|
INKEY |
Non-blocking key check |
KEYDOWN |
TRUE if key is held (graphics mode only) |
MOUSEMIDDLE |
1 if middle button pressed (graphics mode) |
MOUSELEFT |
1 if left button pressed (graphics mode) |
MOUSERIGHT |
1 if right button pressed (graphics mode) |
MOUSEX |
Mouse cursor X position (graphics mode) |
MOUSEY |
Mouse cursor Y position (graphics mode) |
WAITKEY |
Block until key pressed |
Arrays
| Keyword | Description |
|---|---|
DELARRAY |
Remove entire array |
DELKEY |
Remove one array element |
HASKEY |
1 if array element exists |
JOIN |
Merge two arrays; src2$ overwrites src1$ on conflict |
ROWCOUNT |
Return the size of array in first dimension |
Time
| Keyword | Description |
|---|---|
TICKS |
Milliseconds since program start |
TIME |
Current date/time as formatted string |
Logic
| Keyword | Description |
|---|---|
AND |
Logical AND |
FALSE |
0 |
NOT |
Logical NOT |
OFF |
Alias for FALSE (used with SCREENLOCK, VSYNC) |
ON |
Alias for TRUE (used with SCREENLOCK, VSYNC) |
OR |
Logical OR |
TRUE |
1 |
Built-in Constants
These are auto-initialized at startup — no LET
required.
| Constant | Value |
|---|---|
BBVER# |
BazzBasic version string (e.g. "1.1d") |
PRG_ROOT# |
Program base directory path |
TRUE |
1 |
FALSE |
0 |
PI# |
3.14159265358979 |
HPI# |
1.5707963267929895 (π/2) |
QPI# |
0.7853981633974483 (π/4) |
TAU# |
6.283185307179586 (2π) |
EULER# |
2.718281828459045 (e) |
Keyboard constants
KEY_UP# KEY_DOWN# KEY_LEFT#
KEY_RIGHT#
KEY_ESC# KEY_ENTER# KEY_SPACE#
KEY_TAB# KEY_BACKSPACE#
KEY_INSERT# KEY_DELETE# KEY_HOME#
KEY_END# KEY_PGUP#
KEY_PGDN#
KEY_F1# … KEY_F12#
KEY_A# … KEY_Z#
KEY_0# … KEY_9#
KEY_NUMPAD0# … KEY_NUMPAD9#
KEY_LSHIFT# KEY_RSHIFT#
KEY_LCTRL# KEY_RCTRL# KEY_LALT#
KEY_RALT# KEY_LWIN#
KEY_RWIN#
KEY_COMMA# KEY_DOT# KEY_MINUS#
KEY_EQUALS# KEY_SLASH#
KEY_BACKSLASH# KEY_GRAVE#
KEY_LBRACKET# KEY_RBRACKET#
KEY_SEP#