#Imports
Codetoy's API comes in four modules. Import only what you use, either by name or as a namespace. These docs use names for canvas and time, and namespaces for screen and input:
import { fill, rect, circle, text, font } from "codetoy/canvas"
import * as screen from "codetoy/screen" // screen.width(), screen.centerX() ...
import * as input from "codetoy/input" // input.mouseX(), input.isKeyDown() ...
import { deltaTime, elapsedTime } from "codetoy/time"console and Math are global and need no import.
#Number types
AssemblyScript compiles to WebAssembly, so numbers have concrete types:
| Type | Use for |
|---|---|
f64 |
Positions, speeds, angles: almost everything in the API |
i32 |
Counters, indices, mouse buttons, touch ids |
bool |
Flags |
Integer literals default to i32. Give variables an explicit type when you mean a decimal:
let x = 0 // i32! x += 0.5 is a type error
let y: f64 = 0 // what you usually wantConvert between types with as: (i as f64) / 5.0, or <i32>Math.floor(x).
#Strings
Join with + and convert numbers with .toString(). Template literals work too:
console.log("Score: " + score.toString())
text(`FPS: ${Math.round(screen.fps())}`, 10, 10)#Arrays and classes
Arrays are typed: new Array<f64>() or const pts: f64[] = [0, 0, 10, 10]. Classes work like TypeScript classes, including constructor parameter properties.
#Operator overloading
AssemblyScript lets classes define operators, which makes vector math read naturally. The editor's TypeScript checker may underline it, but it compiles and runs:
class Vec2 {
constructor(public x: f64, public y: f64) {}
@operator("+") add(o: Vec2): Vec2 { return new Vec2(this.x + o.x, this.y + o.y) }
@operator("*") scale(s: f64): Vec2 { return new Vec2(this.x * s, this.y * s) }
}
let pos = new Vec2(100, 100)
const vel = new Vec2(120, 40)
export function update(): void {
pos = pos + vel * deltaTime()
}#Differences from TypeScript
- No
any, noundefined, and no union types except nullable classes (Foo | null). - Closures can't capture local variables. Use top-level variables or class fields.
- Annotate the return type of functions you export, e.g.
export function update(): void.
More detail: AssemblyScript concepts and feature status.
#The API is global
Canvas, Screen, Input and Console are static classes available everywhere, with no using needed. Common .NET namespaces like System and System.Collections.Generic are imported implicitly, so Math, List<T> and Dictionary<K, V> just work.
#Properties vs. methods
Values that are always current are fields: Screen.Width, Screen.CenterX, Screen.DeltaTime, Screen.FPS, Input.MouseX. Queries that take an argument are methods: Input.IsKeyDown("a"), Input.TouchX(id).
#Top-level statements
Codetoy supports C# 14, so you can write code directly at the top of the file. A classic static void Main works too.
Declare variables before types
With top-level statements, all variables and statements must come before any class, struct, record or enum declarations. Put your types at the bottom of the file.
// ✓ statements first
double x = 0;
var player = new Player();
Screen.OnUpdate(() => {
player.Draw();
});
// ✓ types last
class Player {
public double X = 100, Y = 100;
public void Draw() => Canvas.Circle(X, Y, 20);
}#Callbacks replace each other
Screen.OnUpdate and every Input.On… method store one callback. Calling it again replaces the previous one, so put all your per-frame logic in a single OnUpdate.
#Logging
Use Console.Log, Console.Warn and Console.Error. Codetoy's Console class shadows System.Console. String interpolation is the easiest way to format: Console.Log($"x = {x:F1}").
#Not available in C# yet
Canvas.Arc, elapsed time, frame count and a resize callback. Track elapsed time yourself by adding up Screen.DeltaTime. Builds and Discord Activities also need AssemblyScript for now.
#Imports
Codetoy's API comes in four modules:
from codetoy.canvas import fill, rect, circle, text, font
from codetoy.screen import width, height, centerX, centerY, fps, frameCount
from codetoy.time import deltaTime, elapsedTime
from codetoy._input import mouseX, mouseY, isKeyDown, isMouseDownimport codetoy.canvas as canvas works too if you prefer canvas.fill(...). Note the input module is codetoy._input, with a leading underscore.
#Python runs on Pyodide
Your code runs in real CPython compiled to WebAssembly (Pyodide). The standard library is available, including math, random, dataclasses, collections and itertools. The first run takes a few seconds while Python loads.
#Event functions are found by name
Define update, resize, keyDown, keyUp, mouseDown, mouseUp, touchStart, touchMove and touchEnd at the top level of your file. Codetoy looks them up after your script runs. Note that the names have no on prefix.
#global is required to assign
Reading a module-level variable inside a function works, but assigning to one creates a new local unless you declare it global:
score = 0
def update():
global score
score += 1Mutating a list or dict doesn't need global: enemies.append(e) is fine.
#Lists for polygons
Pass a plain Python list of numbers to polygon: polygon([x1, y1, x2, y2, x3, y3]).
#Logging
print() writes to the console. Errors and anything printed to sys.stderr show as errors. There's no separate warning level.
#Performance
Python is slower than the compiled languages. Keep the work in update() modest: hundreds of shapes, not tens of thousands. Move heavy setup to module level so it runs once.
#Not available in Python yet
Builds and Discord Activities need AssemblyScript for now.