C# Documentation
Codetoy supports .NET 10 and C# 14 out of the box. It also makes use of top-level statements by default to avoid the typical boilerplate associated with C#.
Top-level statements
In Codetoy you write all C# code using top-level statements. Here is an example of a Codetoy program:
double x = 0;
double speed = 150; // pixels per second
// draw some random rectangle
Canvas.Fill(200, 200, 200);
Canvas.Rect(0, 0, Screen.Width, Screen.Height);
Screen.OnUpdate(() => {
// Clear background
Canvas.Fill(50, 50, 50);
Canvas.Rect(0, 0, Screen.Width, Screen.Height);
// Bounce rectangle
x += speed * Screen.DeltaTime;
if (x + 100 > Screen.Width || x < 0) {
speed = -speed;
}
// Draw rectangle
Canvas.Fill(100, 200, 255);
Canvas.Rect(x, Screen.CenterY - 50, 100, 100);
});
And here is what it would look like if Codetoy didn't use top-level statements:
public class Program
{
double x = 0;
double speed = 150; // pixels per second
public static void Main(string[] args)
{
// draw some random rectangle
Canvas.Fill(200, 200, 200);
Canvas.Rect(0, 0, Screen.Width, Screen.Height);
Screen.OnUpdate(() => {
// Clear background
Canvas.Fill(50, 50, 50);
Canvas.Rect(0, 0, Screen.Width, Screen.Height);
// Bounce rectangle
x += speed * Screen.DeltaTime;
if (x + 100 > Screen.Width || x < 0) {
speed = -speed;
}
// Draw rectangle
Canvas.Fill(100, 200, 255);
Canvas.Rect(x, Screen.CenterY - 50, 100, 100);
});
}
}
Canvas
State Stack
Canvas.Reset()
Canvas.Push()
Canvas.Pop()
Color State
Canvas.Fill(r, g, b, a = 1.0)
Canvas.Stroke(r, g, b, a = 1.0)
Line State
Canvas.LineWidth(double width)
Canvas.LineJoin("round" | "bevel" | "miter")
Canvas.LineMiterLimit(double limit)
Canvas.LineCap("butt" | "round" | "square")
Shape Drawing
Canvas.Rect(x, y, w, h, r = 0)
Canvas.Circle(x, y, radius)
Canvas.Line(x1, y1, x2, y2)
Canvas.Ellipse(x, y, w, h)
Canvas.Triangle(x1, y1, x2, y2, x3, y3)
Canvas.Polygon(double[] points) (eg. x1,y1, x2,y2, ...)
Transform
Canvas.Scale(x, y)
Canvas.Rotate(radians)
Canvas.Translate(x, y)
Canvas.ResetTransform()
Advanced Drawing
Canvas.BeginPath()
Canvas.MoveTo(x, y)
Canvas.LineTo(x, y)
Canvas.BezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y)
Canvas.QuadraticCurveTo(cpx, cpy, x, y)
Canvas.ClosePath()
Canvas.FillPath()
Canvas.StrokePath()
Text
Canvas.Font(family, size, weight = "normal")
Canvas.Text(text, x, y)
Canvas.MeasureText(text) → double (returns width of text)
Input
Mouse
Input.MouseX and Input.MouseY → double
Input.IsMouseDown(button) → bool (0=left, 1=middle, 2=right)
Input.OnMouseDown(Action<int> callback)
Input.OnMouseUp(Action<int> callback)
Keyboard
Input.OnKeyDown(Action<string> callback)
Input.OnKeyUp(Action<string> callback)
Input.IsKeyDown(string key) → bool (if the key is being held down)
Screen
Screen.Width and Screen.Height → double
Screen.CenterX and Screen.CenterY → double
Screen.DeltaTime → double (seconds since last frame)
Screen.FPS -> double
Console
Console.Log(string message)
Console.Warn(string message)
Console.Error(string message)
API Examples
Input API
Static class for handling mouse input and querying mouse position.
Query Methods
Input.IsMouseDown(int button) → bool
Checks if a specific mouse button is currently held down in this frame.
Parameters:
button(int): Mouse button identifier0= Left button1= Middle button (scroll wheel)2= Right button
Return value: (bool) true if the button is currently held down; false otherwise
Example:
Screen.OnUpdate(() => {
if (Input.IsMouseDown(0)) {
Console.Log("Left button is held");
}
});
Input.IsKeyDown(string key) → bool
Checks if a specific key is currently held down in this frame.
Parameters:
key(string) a printable key string as described here
Return value: (bool) true if the key is currently held down; false otherwise
Example:
Screen.OnUpdate(() => {
if (Input.IsKeyDown("UpArrow")) {
Console.Log("UpArrow key is held");
}
});
Properties
Input.MouseX (double)
The current X coordinate of the mouse in canvas space. Updated on mouse movement.
Input.MouseY (double)
The current Y coordinate of the mouse in canvas space. Updated on mouse movement.
Event Handlers
Input.OnKeyDown (Action)
Fired when a key is pressed.
Parameters:
key(string) a printable key string as described here
Example:
Input.OnKeyDown((string key) => {
Console.Log($"Key pressed: {key}");
});
Input.OnKeyUp (Action)
Fired when a key is released.
Parameters:
key(string) a printable key string as described here
Example:
Input.OnKeyUp((string key) => {
Console.Log($"Key released: {key}");
});
Input.OnMouseDown (Action)
Fired when a mouse button is pressed.
Parameters:
button(int): 0 = left, 1 = middle, 2 = right
Example:
Input.OnMouseDown((int button) => {
if (button == 0) {
Console.Log($"Left click at: {Input.MouseX}, {Input.MouseY}");
}
});
Input.OnMouseUp (Action)
Fired when a mouse button is released.
Parameters:
button(int): 0 = left, 1 = middle, 2 = right
Example:
Input.OnMouseUp((int button) => {
Console.Log("Mouse button released");
});
Canvas API
Canvas.Reset()
Clear the entire screen and any previous state for subsequent drawing operations.
Example:
Canvas.Reset();
Canvas.Fill(double r, double g, double b, double a = 1.0)
Sets the fill color for subsequent drawing operations.
Parameters:
r(double): Red channel (0-255)g(double): Green channel (0-255)b(double): Blue channel (0-255)a(double, optional): Alpha/opacity (0-1, default: 1.0)
Example:
Canvas.Fill(255, 0, 0, 0.8); // Semi-transparent red
Canvas.Rect(50, 50, 100, 100);
Canvas.Rect(double x, double y, double w, double h, double r = 0.0)
Draws a rectangle at the specified position with optional rounded corners.
Parameters:
x(double): X coordinate of top-left cornery(double): Y coordinate of top-left cornerw(double): Width of rectangleh(double): Height of rectangler(double, optional): Corner radius for rounding (default: 0)
Example:
Canvas.Fill(0, 150, 255);
Canvas.Rect(100, 100, 200, 150, 10); // Blue rounded rectangle
Canvas.Circle(double x, double y, double radius)
Draws a filled circle at the specified position.
Parameters:
x(double): X coordinate of circle centery(double): Y coordinate of circle centerradius(double): Circle radius in pixels
Example:
Canvas.Fill(100, 255, 100);
Canvas.Circle(Screen.CenterX, Screen.CenterY, 50); // Green circle in center
Canvas.Ellipse(double x, double y, double w, double h)
Draws a filled ellipse at the specified position.
Parameters:
x(double): X coordinate of ellipse centery(double): Y coordinate of ellipse centerw(double): Horizontal radius (half-width) in pixelsh(double): Vertical radius (half-height) in pixels
Example:
Canvas.Fill(255, 200, 0);
Canvas.Ellipse(Screen.CenterX, Screen.CenterY, 80, 40); // Yellow ellipse
Canvas.Triangle(double x1, y1, x2, y2, x3, y3)
Draws a filled triangle with three vertices using the current fill color.
Parameters:
x1, y1(double): First vertex coordinatesx2, y2(double): Second vertex coordinatesx3, y3(double): Third vertex coordinates
Example:
Canvas.Fill(255, 100, 100);
Canvas.Triangle(100, 50, 200, 150, 50, 150);
Canvas.Polygon(double[] points)
Draws a filled polygon by connecting multiple vertices in order. The polygon automatically closes (last point connects back to first).
Parameters:
points(double[]): Array of alternating x,y coordinates:[x1, y1, x2, y2, x3, y3, ...]
Constraints:
- Minimum 6 elements (3 points) required
- Array length must be even
Example:
Canvas.Fill(100, 200, 255);
double[] pentagon = {
150, 50, // top
230, 110, // top-right
190, 190, // bottom-right
110, 190, // bottom-left
70, 110 // top-left
};
Canvas.Polygon(pentagon);
Canvas.Font(string family, double size, string weight = "normal")
Sets the font for subsequent text rendering. Font settings persist until changed.
Parameters:
family(string): Font family name. Examples: "Arial", "Georgia", "Courier New", "sans-serif", "monospace"size(double): Font size in pixels. Typical range: 10–48weight(string, optional): Font weight. Valid values: "normal", "bold", "lighter", or numeric values "100"–"900" (default: "normal")
Note: Text color is determined by the current fill color set with Canvas.Fill(). See Canvas.Text() and Canvas.MeasureText() for related methods.
Example:
Canvas.Fill(0, 0, 0); // Black text
Canvas.Font("Arial", 24, "bold");
Canvas.Text("Hello World", 50, 50);
Canvas.Text("Another line", 50, 80); // Uses same font settings
Canvas.Text(string content, double x, double y)
Draws text at the specified position using the current font settings and fill color.
Parameters:
content(string): The text string to renderx(double): X coordinate of the text position (left edge) in pixelsy(double): Y coordinate of the text position (top edge) in pixels
Requires: Canvas.Font() should be called at least once before using Canvas.Text().
Example:
Canvas.Fill(255, 255, 255); // White text
Canvas.Font("Georgia", 20);
Canvas.Text("Score: 100", 10, 30);
Canvas.MeasureText(string content) → double
Returns the width in pixels of text rendered with the current font settings. Useful for layout calculations and centering text.
Parameters:
content(string): The text string to measure
Return value: (double) Width in pixels
Requires: Canvas.Font() must be called before Canvas.MeasureText() to ensure correct measurement.
Example: Centering text horizontally
Canvas.Font("Arial", 18);
string message = "Centered Text";
double textWidth = Canvas.MeasureText(message);
double xPos = Screen.CenterX - textWidth / 2;
Canvas.Fill(0, 0, 0);
Canvas.Text(message, xPos, Screen.Height / 2);
Screen API
Static class for managing the drawing canvas and the update loop.
Properties
Screen.Width (double)
The current canvas width in pixels. Updates when the window is resized.
Screen.Height (double)
The current canvas height in pixels. Updates when the window is resized.
Screen.CenterX (double)
The horizontal center of the canvas in pixels, equal to Screen.Width / 2. Convenience property that updates when the window is resized.
Screen.CenterY (double)
The vertical center of the canvas in pixels, equal to Screen.Height / 2. Convenience property that updates when the window is resized.
Screen.DeltaTime (double)
The time elapsed since the last frame in seconds. Useful for smooth, frame-rate-independent animations.
Screen.FPS (double)
The current frames per second being rendered. Useful for performance monitoring and diagnostics.
Event Handlers
Screen.Update (Action)
Fired every frame. Use this for animations and game logic.
Example:
Screen.OnUpdate(() => {
Canvas.Fill(255, 100, 0);
Canvas.Circle(Input.MouseX, Input.MouseY, 20); // Follow cursor
});
Console API
Console.Log(string message)
Logs a message to the browser console.
Parameters:
message(string): The message to log
Example:
Console.Log("Application started");
Console.Warn(string message)
Logs a warning message to the browser console.
Parameters:
message(string): The warning message
Example:
Console.Warn("Performance may be degraded");
Console.Error(string message)
Logs an error message to the browser console.
Parameters:
message(string): The error message
Example:
Console.Error("Invalid input detected");
Example Programs
Example 1: Interactive Circle Following Cursor
Canvas.Fill(200, 200, 200);
Canvas.Rect(0, 0, Screen.Width, Screen.Height);
Screen.OnUpdate(() => {
Canvas.Fill(200, 200, 200);
Canvas.Rect(0, 0, Screen.Width, Screen.Height); // Clear background
Canvas.Fill(0, 150, 255);
Canvas.Circle(Input.MouseX, Input.MouseY, 30); // Blue circle follows mouse
});
Input.OnMouseDown((int button) => {
Console.Log($"Clicked at {Input.MouseX}, {Input.MouseY}");
});
Example 2: Animated Rectangle
double x = 0;
double speed = 150; // pixels per second
Screen.OnUpdate(() => {
// Clear background
Canvas.Fill(50, 50, 50);
Canvas.Rect(0, 0, Screen.Width, Screen.Height);
// Bounce rectangle
x += speed * Screen.DeltaTime;
if (x + 100 > Screen.Width || x < 0) {
speed = -speed;
}
Canvas.Fill(100, 200, 255);
Canvas.Rect(x, Screen.CenterY - 50, 100, 100);
});
Example 3: Responsive Grid
int cols = 5;
int rows = 4;
Screen.OnUpdate(() => {
Canvas.Fill(30, 30, 30);
Canvas.Rect(0, 0, Screen.Width, Screen.Height); // Background
double cellWidth = Screen.Width / cols;
double cellHeight = Screen.Height / rows;
for (int row = 0; row < rows; row++) {
for (int col = 0; col < cols; col++) {
Canvas.Fill(100 + col * 30, 100 + row * 30, 200);
Canvas.Rect(col * cellWidth, row * cellHeight, cellWidth, cellHeight, 5);
}
}
});
Example 4: Drawing with Mouse
var points = new List<(double x, double y)>();
Screen.OnUpdate(() => {
Canvas.Fill(40, 40, 40);
Canvas.Rect(0, 0, Screen.Width, Screen.Height); // Clear background
// Draw all recorded points
Canvas.Fill(255, 100, 100);
foreach (var point in points) {
Canvas.Circle(point.x, point.y, 5);
}
});
Input.OnMouseDown((int button) => {
if (button == 0) {
points.Add((Input.MouseX, Input.MouseY));
}
});
Example 5: Pulsing Ellipses
using System;
double time = 0;
Screen.OnUpdate(() => {
Canvas.Fill(20, 20, 30);
Canvas.Rect(0, 0, Screen.Width, Screen.Height); // Background
time += Screen.DeltaTime;
for (int i = 1; i <= 5; i++) {
double delay = i * 0.2;
double scale = 1 + Math.Sin(time * 3 - delay) * 0.5;
Canvas.Fill(100 + i * 30, 150, 200);
Canvas.Ellipse(Screen.CenterX, Screen.CenterY, 40 * scale, 20 * scale);
}
});
Example 6: Text Rendering and Centered Layout
Screen.OnUpdate(() => {
Canvas.Fill(240, 240, 240);
Canvas.Rect(0, 0, Screen.Width, Screen.Height); // Background
// Centered title
Canvas.Fill(0, 0, 0);
Canvas.Font("Arial", 32, "bold");
string title = "Codetoy Playground";
double titleWidth = Canvas.MeasureText(title);
Canvas.Text(title, Screen.CenterX - titleWidth / 2, 40);
// Subtitle
Canvas.Font("Arial", 14);
Canvas.Text("Interactive Graphics in C#", 20, 90);
// FPS counter
Canvas.Font("monospace", 12);
Canvas.Fill(100, 100, 100);
Canvas.Text($"FPS: {Screen.FPS:F1}", 10, Screen.Height - 20);
});
Example 7: Shapes Gallery
using System;
Screen.OnUpdate(() => {
Canvas.Fill(20, 20, 30);
Canvas.Rect(0, 0, Screen.Width, Screen.Height); // Background
// Triangle (left)
Canvas.Fill(255, 100, 100);
Canvas.Triangle(100, 80, 150, 180, 50, 180);
// Pentagon (center)
Canvas.Fill(100, 200, 255);
double[] pentagon = { 300, 50, 360, 110, 330, 180, 270, 180, 240, 110 };
Canvas.Polygon(pentagon);
// Hexagon (right, centered)
Canvas.Fill(150, 255, 100);
double cx = Screen.CenterX + 150;
double cy = Screen.CenterY;
double radius = 60;
double[] hexagon = new double[12];
for (int i = 0; i < 6; i++) {
hexagon[i * 2] = cx + radius * Math.Cos(i * Math.PI / 3);
hexagon[i * 2 + 1] = cy + radius * Math.Sin(i * Math.PI / 3);
}
Canvas.Polygon(hexagon);
});
