Yeah, I was rather intentionally cryptic about that since I have a very-very drafty document on this I started the work on the compiler. Still on a bit of back-and-forth on this, but I can show you what is the current draft.
The main TLDR idea is:
A sort of BASIC that is able to support curly bracket contexts, mainly to define functions or loops (for/while) or even native assembly.
Global variables only (at least for now), arrays of some basic types
basic types: int, float, string, color, sprite, audio.
I think I might also consider first implementing a more simple actual BASIC language.
It will still be a powerful gain since there will be a compiler, not an interpreter, so the code will end-up as native assembly, so very fast.
Here’s the very drafty thing:
MOSAIC Language Overview
A concise reference to MOSAIC’s core features, data types, memory layout, control flow constructs, system functions, and sample code.
MOSAIC stands for Medium Omni-language Symbolic Advanced Instruction Code. While the acronym is a creative backronym, the real purpose of MOSAIC is to serve as a simple, fast, game-oriented high-level language targeting the fantasy retro computer emulator Continuum 93.
Continuum 93 is a custom fantasy computer built for retro game development, with a custom CPU and assembly language loosely inspired by the Z80, but modernized. It was developed in C# using MonoGame, and features an assembly instruction set tailored for performance and game logic.
MOSAIC began as a project to create a BASIC-like compiler for this architecture but evolved into a more structured, C#-inspired language designed to simplify game development on the platform. It supports special game-related data types like sprite, and in the future may support DOS-like filesystem commands and inline assembly blocks (asm { … }).
1. Data Types & Declarations
Color Palettes
Each of Continuum’s 8 video layers has its own palette, defined as an array of 256 color values. These palettes are directly accessible and modifiable in user code:
color layer0Palette
layer0Palette[0] = color(255, 0, 0) // Set first color to red
Primitive Types (static)
bool flag // 1 bit true/false
int score // 32‑bit signed integer
float speed // 32‑bit IEEE‑754 float
byte raw // 8-bit unsigned integer
color tint // 24-bit color (8-bit red, green, blue)
Reference Types (heap‑allocated handles, 4 bytes each)
string name // heap object (length & buffer)
sprite spriteObj // heap object + VRAM pixel data
Composite Types
Arrays: dynamic, growable buffers of any element type
int numbers
string names
sprite frames
color palette
2. Memory Organization
- Data Segment (static)
-
All primitive variables and arrays (initial header + fixed buffer) are allocated at compile time with labels.
-
Primitive arrays (int, float): the buffer stores inline values (4 bytes each) contiguously.
-
Boolean arrays (bool): use bit‑packed storage (1 bit per element) with direct hardware support via GETBIT(addr) addressing, where addr = byteIndex * 8 + bitIndex for O(1) access.
-
Reference arrays (string, sprite, or any handle type): the buffer stores 4‑byte handles (pointers) contiguously; each handle refers to a heap object.
Example:
.var_score: .word 0 ; int score
.numbers_len: .word 0 ; array length
.numbers_cap: .word 4 ; array capacity
.numbers_data: .skip 4 * 4 ; 4 ints inline
.names_len: .word 0 ; array length
.names_cap: .word 2 ; initial capacity
.names_data: .word 0, 0 ; 2 handles to string objects
- Heap (dynamic)
-
string objects: header (length, capacity) + UTF‑8 buffer
-
sprite objects: metadata struct in RAM + pixel bitmaps in VRAM
-
Array growth: if an array’s length exceeds its static capacity, a dynamic buffer is allocated or resized on the heap (header & data), preserving existing slots.
- VRAM Region
- Pixel bitmaps for sprite, managed separately via LoadSprite and FreeSprite
3. Operators & Expressions
MOSAIC supports typical arithmetic and logical operators used in expressions and control structures. Expressions follow C-style operator precedence.
Arithmetic Operators:
Unary Operators:
-
-x Negation
-
+x Unary plus (no-op)
Comparison Operators:
-
== Equal to
-
!= Not equal to
-
Greater than
-
= Greater than or equal to
-
< Less than
-
<= Less than or equal to
Logical Operators:
-
&& Logical AND
-
|| Logical OR
-
! Logical NOT
Bitwise Operators:
-
& Bitwise AND
-
| Bitwise OR
-
^ Bitwise XOR
-
~ Bitwise NOT
-
<< Shift left
-
Shift right
Assignment Operators:
-
= Assignment
-
+=, -=, *=, /=, %= — Compound arithmetic assignments
-
&=, |=, ^=, <<=, >>= — Compound bitwise assignments
Expression Notes:
-
Mixed int and float operations are allowed; results follow the wider type (e.g., int + float → float).
-
Parentheses () can be used to control evaluation order, e.g., (a + b) * c
-
The ^ symbol is for bitwise XOR — use sqr(x) for power or root calculations via system functions.
3. Control Flow
If / Else
if (hp <= 0) {
print(“Game Over”, 0, 0)
} else {
print(“HP:”, hp, 0, 0)
}
While Loop
while (running) {
update()
render()
}
For Loop
for (int i = 0; i < 10; i += 1) {
print(i, i*8, 0)
}
Switch / Case
select (level) {
case (0) print(“Novice”, 0,0)
case (1) print(“Adept”, 0,0)
default print(“Master”, 0,0)
}
Break / Continue supported inside loops:
for (int i = 0; i < 100; i += 1) {
if (i == 50) break
if (i % 2 == 0) continue
print(i, 0, i*4)
}
4. Functions
User‑defined, non‑recursive, with static locals & parameters:
int Clamp(int v, int lo, int hi) {
if (v < lo) return lo
if (v > hi) return hi
return v
}
// Usage:
int x = Clamp(player.x, 0, screenWidth - 1)
5. Array Utilities
int ArrayCount(T arr) // current length
void ArrayResize(T arr, int n) // set length (grow/truncate)
void ArrayAdd(T arr, T v) // append v
void ArrayRemove(T arr, int i) // delete index i, shift left
// Example
int nums
print(ArrayCount(nums)) // 0
ArrayResize(nums, 5) // length=5
nums[4] = 42 // OK
ArrayAdd(nums, 7) // length=6, nums[5]=7
ArrayRemove(nums, 2) // remove slot 2
6. System Functions
These functions will be expanded as needed to support common game development tasks. Time and input handling, audio playback, and string manipulation are also planned.
Math Functions:
-
blendcolors(c1, c2, t) — linearly interpolates between two colors c1 and c2 using t (0.0 to 1.0)
-
darken(color, amount) — reduces brightness by amount (0–1)
-
lighten(color, amount) — increases brightness by amount (0–1)
-
rgb2hsl(r, g, b) — converts 0–255 RGB to HSL components
-
hsl2rgb(h, s, l) — converts HSL to 0–255 RGB
-
rgb2hsb(r, g, b) — converts RGB to HSB
-
hsb2rgb(h, s, b) — converts HSB to RGB
-
min(a, b), max(a, b)
-
round(x), floor(x), ceil(x)
-
random(min, max)
-
sqr(x) (square root), cbr(x) (cube root), isqr(x) (inverse square root)
-
sin(x), cos(x), tan(x)
-
abs(x)
-
sign(x) — returns -1, 0, or 1
-
mod(a, b) — modulo operation
-
lerp(a, b, t) — linear interpolation
-
atan2(y, x) — angle from coordinates
-
degToRad(x), radToDeg(x) — angle conversions
Bit Manipulation:
-
and(a, b), or(a, b), xor(a, b)
-
nand(a, b), nor(a, b), xnor(a, b)
-
not(x), set(val, bit), reset(val, bit), toggle(val, bit)
-
shiftLeft(val, n), shiftRight(val, n)
-
rollLeft(val, n), rollRight(val, n)
Input Handling:
Keyboard:
-
keyDown(key) — true while held
-
keyUp(key) — true when not held
-
keyPressed(key) — true only on initial press
-
keyReleased(key) — true only on release
-
keyPressedFor(key, ms) — true if held for specified milliseconds
-
getPressedKeys() — returns array of currently held keys (ASCII codes)
Mouse:
-
mouseX(), mouseY() — current mouse coordinates
-
mouseDeltaX(), mouseDeltaY() — movement since last frame
-
mouseButtonDown(button), mouseButtonPressed(button) — same semantics as keyboard
-
mouseWheelDelta() — scroll movement since last frame
Gamepad (1–4):
-
gamepadConnected(index) — check if connected
-
gamepadButtonDown(index, button) — held
-
gamepadButtonPressed(index, button) — just pressed
-
gamepadAxis(index, axis) — analog axis value (e.g., stick, trigger)
-
gamepadVibrate(index, intensity, durationMs) — trigger vibration
Time Functions:
-
getTimeMs() — returns milliseconds since system boot (32-bit)
-
getTimeTicks() — returns CPU ticks since boot (64-bit)
-
wait(ms) — delays execution for specified milliseconds (non-blocking if possible)
-
deltaTime() — returns ms between current and last frame (for smooth animations)
-
timeSince(timestamp) — calculates elapsed ms since a previous getTimeMs() value
Memory Functions:
-
getPointer(array) — returns the memory address of the first element of the array (e.g., for execution or binary manipulation)
-
peek(addr) — reads a byte at the given memory address
-
poke(addr, value) — writes a byte to the given memory address
-
copyMem(dest, src, size) — copies a block of memory (size in bytes) from src to dest
-
fillMem(addr, value, size) — fills a memory block starting at addr with value, for size bytes
-
compareMem(addr1, addr2, size) — compares memory regions, returns 0 if equal, or difference value
-
memSetZero(addr, size) — optimized zero-fill utility
Filesystem Functions:
-
fileExists(path) — returns true if a file exists
-
dirExists(path) — returns true if a directory exists
-
createFile(path) — creates an empty file (or truncates if exists)
-
createDir(path) — creates a new directory
-
deleteFile(path) — removes a file
-
deleteDir(path) — removes a directory
-
listDir(path) — returns array of filenames in directory
-
getFileSize(path) — returns size of file in bytes
-
readTextFile(path) — reads an entire file as string
-
writeTextFile(path, content) — writes full content to file
-
appendTextFile(path, content) — appends string to file
-
readBytes(path) — returns byte with file data
-
writeBytes(path, byte) — writes byte to file
-
openFile(path, mode) — opens a file handle in mode: “r”, “w”, “a”, “rb”, etc.
-
readLine(file) — reads next line from file
-
writeLine(file, text) — writes a line to file
-
readByte(file) / writeByte(file, b) — raw byte operations
-
readInt(file) / writeInt(file, i) — 32-bit int
-
readFloat(file) / writeFloat(file, f) — 32-bit float
-
seek(file, pos) — move file cursor to byte offset
-
tell(file) — get current byte offset
-
closeFile(file) — closes open file handle
Execution Functions:
- exec(addr) — executes machine code starting at the given memory address. Used for running custom-loaded routines or assembly programs dynamically.
Sound Functions:
WAV Playback:
Synth SFX (SFXR-style):
-
playSfx(type) — plays a preset synthetic sound (e.g., “laser”, “pickup”, “jump”)
-
playSfxCustom(params) — plays a sound using a parameter structure or map
-
stopSfx() — halts any playing synthesized effect
-
setSfxVolume(level) — sets volume for synthesized output (0–100)
-
setSfxParam(name, value) — allows real-time tweaking of a single sound parameter (e.g., frequency, decay)
Graphics Primitives:**
-
drawLine(x1, y1, x2, y2) — alias for clarity
-
drawCircle(x, y, r) — shorthand for symmetric ellipse
-
drawText(text, x, y) — general-purpose text output
-
clear(color) — fills screen background
-
setPixel(x, y, color) — explicit pixel draw**
-
drawRect(x, y, w, h)
-
drawFilledRect(x, y, w, h)
-
drawEllipse(x, y, rx, ry)
-
plot(x, y)
-
line(x0, y0, x1, y1)
-
fill(x, y)
7. Sample Program
// Bouncy ball demo
sprite ball = LoadSprite(“ball.spr”)
int x = 100
int y = 100
int pathX
int pathY
// build path
ArrayAdd(pathX, 50)
ArrayAdd(pathY, 50)
ArrayAdd(pathX, 150)
ArrayAdd(pathY, 80)
while (true) {
clearScreen()
print(ball, x, y)
for (int i = 0; i < ArrayCount(pathX); i += 1) {
print(“.”, pathX[i], pathY[i])
}
}