2025, Merthsoft Creations
Tuga is a turtle programming language designed around the TI-84+CE graphing calculator. It's meant to be simple to learn and read while still providing enough power to make cool fractals and learn about programming. The specification itself is "missing" many things that would otherwise be necessary--this is intentional, this language is designed around existing functionailty on the TI-84+CE, and will reuse what's possible.
TUGA is the accompanying interpreter. It uses the built-in program format as its container, and reuses the operating system variables and math evaluation. It aims to provide a turtle language that can be programmed on the calculator easily, and integrates with the OS as seamlessly as possible.
Github: https://github.com/merthsoft/tugace/
Alpha: https://merthsoft.com/tuga/Tuga.zip
The only constant is change. But right now, especially, things can change very quickly. This document may be out of date with the code base, but I'll do my best.
You'll need a TI-84+CE that's had artifice run on it, as well as ASMHOOK.
Send TUGA and the sample programs to your calculator. Run TUGA. You should see a shell showing you the available programs. Use the arrow keys to select a program and press enter to run it. Alternatively, most programs have self-launching, so you can run the program from the homescreen.
Once the program has finished, it will be in the "DONE" state. Alternatively, while TUGA is running, you can press "MODE", "DEL", or "CLEAR" to be put in the done state. This is the same as a program running the "STOP" command.
Once in the done state, press "MODE", "DEL", or "CLEAR" to quit, or "ENTER" to restart the program.
While the program is running, press "ENTER" to pause execution.
Programs should start with 0TUGA
to be recognized by the shell. It's recommended that you at the very least include :Return
after 0TUGA
, so it doesn't function as a TI-BASIC program. Additionally, it supports self-launching, so you can still do:
0TUGA:"PROGNAME":Asm(prgmPROGNAME:Return
Or any amount of BASIC code on the first line that you want, really.
0TUGA:"PROGNAME":Asm(prgmTUGA:Return
"Description
TUGA:"PROGNAME":Asm(prgmTUGA:Return
:HEX ICON
"Description
Icon is a 16x16 BASIC palette sprite (similar to DCS header).
For sub-programs, just leave out "0TUGA", and make the first line just "Return" (so it doesn't work as a BASIC program).
You have access to the variables A-Z and Theta for storing. Additionally, the variables are the system variables. If you do 1->A
before running your program, and your program is INC A
, then on the homescreen of TI-OS you check the value of A
, it will be 2
. Lists can be used for parameters, but can't currently be directly written to. Eventually, STO
will work on Real, List, Matrix, and String types.
Commands are typed in all caps and parameters are evaluated using the OS evaluation. Commands with {
are expecting a list. Commands that don't accept lists can take a list, and only the first element will be used.
Because TUGA uses the OS evaluation, your parameters can be formulas--and they can even be complex (imaginary value is truncated before passed on to the turtle itself). This means you can do COLOR randInt(0, 255
to set the turtle to a random color.
Comments start with "
and are skipped entirely.
Command | Description |
---|---|
TURTLE [num] | Sets which turtle commands operate on |
COLOR [color] | Sets the turtle color to [color] |
PEN [status] | Sets the turtle pen status to [status] |
WRAP [status] | Sets the turtle wrap status to [status] |
FORWARD [amt] | Moves the turtle forward by [amt] |
LEFT [amt] | Turn left by [amt] degrees |
RIGHT [amt] | Turn right by [amt] degrees |
MOVE {[X],[Y] | Moves to [X, Y] |
ANGLE [amt] | Sets angle to [amt] degrees |
INIT | Initializes the turtle, moving it the center of the screen, setting the color to 255, and setting the pen to 1 |
Command | Description |
---|---|
CLEAR [color] | Clears the screen with [color] |
FILL | Does a flood fill at the turtle's location of the current color |
FADEOUT [step] | Fades out at a rate of [step] |
FADEIN [step] | Fades in at the rate of [step] |
INIT | Resets the current turtle to the initial conditions |
RECT {[w],[h] | Draws a rectangle with upper-left corner at the turtle's location that's [w] by [h] |
CIRCLE [radius] | Draws a circle of radius [radius] centered around the turtle |
ELLIPSE {[radiusX],[radiusY] | Draws an ellipse of radius [radiusX],[radiusY] centered around the turtle |
ELLIPSE {[x],[y],[radiusX],[radiusY] | Draws an ellipse of radius [radiusX],[radiusY] centered around (x, 1) |
TEXT [str] | Writes [str] to the screen at turtle position |
DRAWSCREEN | Draws to the screen |
DRAWBUFFER | Draws to the buffer |
SWAPDRAW | Swaps the screen and buffer |
Command | Description |
---|---|
DEFSPRITE "[index],[w],HEX SPRITE DATA" | Defines a sprite, allocating it as needed, adding at [index] in the sprite dictionary. Height is assumed by length. |
SPRITE [num] | Sets the turtle to be sprite [num] in the sprite dictionary |
Command | Description |
---|---|
PALETTE {[num],[param1],[param2] | Sets the palette. Currently supports 0 for default |
PALSHIFT | Shifts the palette by 1 |
Number | Palette |
---|---|
0 | Default |
1 | Rainbow |
2 | Monochrome |
Label names should be all-caps.
Command | Description |
---|---|
LABEL [name] | Declares label [name] |
GOTO [name] | Goes to label named [name] |
LABEL [number] | Declares label [number] |
GOTO [number] | Goes to label number [number] |
IF [val] | Skips the next line if [val] is 0 |
GOSUB [name] | Goes to label named [name], pushing the the next line onto the system stack |
GOSUB [number] | Goes to label [number], pushing the the next line onto the system stack |
RET | Returns to where you jumped from, popping that value off the system stack |
STOP | Ends the program |
Command | Description |
---|---|
GETKEY | Gets the current key to Ans |
GETKEY [var] | Gets the current key to [var] |
KEYDOWN [key] | Sets ans to 1 if the key is down, otherwise 0 (BASIC key code) |
KEYUP [key] | Sets ans to 1 if the key is UP, otherwise 0 (BASIC key code) |
IFKEYDOWN [key] | Processes the next line if the key is down (BASIC key code) |
IFKEYUP [key] | Processes the next line if the key is UP (BASIC key code) |
Command | Description |
---|---|
STACK [num] | Operates which stack commands operate on |
PUSH [val] | Pushes [val] onto the stack |
PUSH [list] | Pushes a list onto the stack |
POP | Pops off the stack into Ans |
POP [var] | Pops off the stack into [var] |
PEEK | Peeks at the stack into Ans without changing the stack pointer |
PEEK [var] | Peeks at the stack into [var] without changing the stack pointer |
PUSHVEC | Pushes the entire turtle vector (x, y, angle) onto the stack |
POPVEC | Pops the turtle vector off the stack, setting the current turtle's values to that |
PEEKVEC | Peeks the turtle vector from the stack, setting the current turtle's values to that without changing the stack pointer |
Command | Description |
---|---|
ZERO [var] | Sets real var [var] to zero |
INC [var] | Increments real var [var] by one |
INC {[var],[val] | Increments real var [var] by [val] |
DEC [var] | Decrements real var [var] by one |
DEV {[var],[val] | Decrements real var [var] by [val] |
STO {[var],[val] | Stores [val] to real var [var] |
Command | Description |
---|---|
SPEED [val] | Sets the turtle's auto-movement speed. Effective call FORWARD [val] each frame, evaluated when set |
SCALE {[x],[y] | Sets the turtles sprite scale |
TRANS | Flags the sprite as to be draws as transparent |
PEN {[fg],[bg] | Can set the background color of text |
Command | Description |
---|---|
STO [var] | Stores Ans to [var] |
EVAL [code] | Evaluates arbitrary BASIC code in [code] |
ASM [code] | Runs ASM [code] |
FORWARD {[X],[Y] | Disregards angle, and just moves to {x + [X], y + [Y]} |
KEYS [val] | Allows users to disable quit and pause keys |
Command | Description |
---|---|
RESET | Reset the program |
JNZ {[val],[label] | Jumps to [label] if [val] isn't zero |
DJNZ {[var],[label] | Decrements [var] and jumps to [label] if the result is non-zero |
PROG [program] | Runs [program] as a Tuga program |
Command | Description |
---|---|
STACK -1 | Select the system stack for stack commands |
PUSHPC | Pushes PC of the command after this one onto the system stack |
POP [list] | If [list] is a list of real vars, pops into those real vars, if it's a list var, pops into that list var |
PEEK [list] | If [list] is a list of real vars, pops into those real vars, if it's a list var, pops into that list var |
POP {[count] | Pops [count] items off the stack returned as a list in ans |
PEEK {[count] | Peeks at [count] items from the stack returned as a list in ans |
PEER [index] | Returns the stack value in [index] in ans |
PEER {[index],[count] | Returns the value in [index] through [index]+[count] |
PROD {[index],[val0],[val1]... | Writes [valx] to stack at [index + x] |
Command | Description |
---|---|
LINE {[x1],[y1],[x2],[y2] | Draws a line from (x1, y1) to (x2, y2) |
RECT {[x1],[y1],[w],[h] | Draws a rectangle at (x1, y1) that's w by h |
PERF [val] | Turns off the performance counter if [val] is 0 |
BLITSCREEN | Blits the screen to the buffer |
BLITBUFFER | Blits the buffer to the screen |
TRANSINDEX [val] | Sets the transparent index |
TEXTTRANSINDEX [val] | Sets the transparent index for text |
Command | Description |
---|---|
LOADSPRITES "[APPVAR] | Loads a sprite dictionary from [APPVAR] |
SPRITE {[num],[x],[y],[xScale],[yScale] | Draws sprite [num] at [x],[y] [xScale],[yScale] |
ROTSPRITE {[num],[x],[y],[rotation],[scale] | Draws sprite [num] at [x],[y], rotated, with optional [scale] |
TRANSSPRITE {[num],[x],[y],[xScale],[yScale] | Draws sprite [num] at [x],[y] [xScale],[yScale] |
TRANSROTSPRITE {[num],[x],[y],[rotation],[scale] | Draws sprite [num] at [x],[y], rotated, with optional [scale] |
DEFTILEMAP "[w],HEX TILEMAP DATA" | Defines the hex tilemap data |
TILEMAP {[x],[y],[map_x],[map_y],[view_width],[view_height] | Draws a tilemap at [x],[y] on the screen, offset at [map_x],[map_y] of [view_width]x[view_height] tiles |
Command | Description |
---|---|
DEFPAL [list] | Sets the palette to [list] |
DEFPAL [hex] | Sets the palette to data in [hex] string |
PALSHIFT {[start], [amount], [length] | Shifts the palette starting at [start] ending at [start] + [length] by [amount], [amount] and [length] are optional and default to 1 and the full palette length |
Number | Palette |
---|---|
3 | Monochromatic HSV saturation-spectrum, takes two additional params, color and direction |
4 | Monochromatic HSV value-spectrum, takes two additional params, color and direction |
5 | Random, takes direction |
6 | Spectrum, takes direction and hue skip |
Symbol | Command |
---|---|
+ | INC |
- | DEC |
{ | PUSH |
} | POP |
small E | PEEK |
[u] | PEER |
[v] | PROD |
e | EVAL |
-> | STO |
: | LABEL |
. | GOTO |
* | GOSUB |
/ | RET |
^ | FORWARD |
pi | MOVE |
( | LEFT |
) | RIGHT |
[ | PUSHVEC |
] | POPVEC |
= | PEEKVEC |
? | IF |
imaginary i | COLOR |
angle | ANGLE |
single-quote | SPEED |
^r | SPRITE |
X | TURTLE |
0 | ZERO |
theta | STACK |
< | FADEOUT |
> | FADEIN |
= | DEFSPRITE |
!= | DEFTILEMAP |
Symbol | Command |
---|---|
^2 | |
^-1 | |
sin( | |
cos( | |
tan( | |
log( | |
ln( | |
sin^-1( | |
cos^-1( | |
tan^-1( | |
sqrt( | |
10^x | |
[w] | |
e^( |
Symbol | Command |
---|---|
<= | |
>= |
Some additional conveniences from programming commands, space built in to token:
Symbol | Command |
---|---|
Goto | GOTO |
If | IF |
Lbl | LABEL |
Stop | STOP |
getkey | GETKEY |
LEFT | LEFT |
PO[PV]EC | POPVEC |
Subroutines are defined as labels, contain code, and end with RET
:
LABEL SUBROUTINE
" CODE
RET
And invoked with GOSUB
: GOSUB SUBROUTINE
. When you do this, the line after the GOSUB is pushed onto the system stack, and the program flow goes to the label. When it encounters RET
, the address is popped off the stack, and program flow returns to that address. This lets you jump to a block of code and return where execution was. All variables are shared, so it's up to you manage all that.
Functions are defined with FUNC
, a name, and a list of parameters, and end with RET
:
FUNC FUNCTION(A,B,C
" CODE
RET
And invoked with CALL
: CALL FUNCTION(X,Y,Z
. The function is re-writte as
LABEL FUNCTION
" `SYSPUSH` pushes onto the system stack
SYSPUSH {A,B,C
" This is on the selected stack
PEEK {A,B,C
" CODE
" `SYSPOP` pops off the system stack
SYSPOP {A,B,C
RET
PUSH {X,Y,Z
GOSUB FUNCTION
POP {X,Y,Z
Alternatively, all push and pop commands could happen on the system stack.
Parameterless commands should operate on the stack, or there should be a way to say so. e.g. FOWARD
should pop a value off the stack and move forward that amount. STO K
should pop off the stack and store to K. Etc.
Hex strings are strings of characters, 0-9 and A-F. Every two characters is one byte.
Sprites are stored as a byte per pixel, from left to right, top to bottom (column major).
In a sprite dictionary AppVar, for each sprite, there's a byte for width, a byte for height, and then the sprite data in column-major format.
This will loosely match the toolchain tilemap format.
Still needs a lot of design work. Probably when a program gets invoked, it gets loaded and copied after the executing program.
PC gets pushed and jumps to sub program, much like a GOSUB.
Sub program needs to call RET or else execution stops entirely.
Programs share stack.
We need a way to preserve labels between programs. This could be the system stack, but that's potentially a lot of wasted data if we do that naively (just pushing the label vector).
Labels could be shared between programs.