Codetoy.io
Click to Draw

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 identifier
    • 0 = Left button
    • 1 = 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 corner
  • y (double): Y coordinate of top-left corner
  • w (double): Width of rectangle
  • h (double): Height of rectangle
  • r (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 center
  • y (double): Y coordinate of circle center
  • radius (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 center
  • y (double): Y coordinate of ellipse center
  • w (double): Horizontal radius (half-width) in pixels
  • h (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 coordinates
  • x2, y2 (double): Second vertex coordinates
  • x3, 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–48
  • weight (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 render
  • x (double): X coordinate of the text position (left edge) in pixels
  • y (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);
});
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);
});