# Codetoy documentation (C#)

<!-- https://codetoy.io/docs -->
# Introduction

There's nothing to install and no project to configure. You write one file, press **Play**, and your code draws onto a canvas immediately. When it's ready, share a link, embed it on a website, or publish a [build](/docs/builds) your friends can play inside [Discord](/docs/discord).

```cs
Screen.OnUpdate(() => {
    Canvas.Fill(20, 20, 30);
    Canvas.Rect(0, 0, Screen.Width, Screen.Height);

    Canvas.Fill(100, 180, 255);
    Canvas.Circle(Input.MouseX, Input.MouseY, 24);
});
```

That's a complete program: a circle that follows your mouse.

> **AssemblyScript is recommended:** AssemblyScript is TypeScript-like syntax that compiles to small, fast WebAssembly. It's the only language that supports [Builds](/docs/builds) and [Discord Activities](/docs/discord) today. If you're not sure which to choose, start here. [Compare languages →](/docs/languages)

## How Codetoy works

- **One file.** Your whole program lives in a single script. There are no scenes, objects or assets to set up.
- **Immediate-mode drawing.** Every frame, you clear the canvas and draw what should be on screen. The API is modeled on the HTML [`CanvasRenderingContext2D`](https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D), so if you've drawn on a web canvas, you already know it.
- **An update loop and events.** Codetoy calls your `Screen.OnUpdate()` every frame and notifies you of keyboard, mouse and touch input.
- **Runs in the browser.** Code compiles to WebAssembly (or runs on Pyodide for Python) right in the page.

## Next steps

- [Quickstart](/docs/quickstart) — Build your first interactive codetoy in a few minutes.
- [Choosing a Language](/docs/languages) — How AssemblyScript, C# and Python compare.
- [Program Structure](/docs/program-structure) — Setup code, the update loop and events.
- [Canvas API](/docs/api/canvas) — Every drawing function, with examples.
- [Builds](/docs/builds) — Save a hosted, playable version of your game.
- [Discord Activities](/docs/discord) — Play your game with friends in a Discord call.

---

<!-- https://codetoy.io/docs/quickstart -->
# Quickstart

This guide takes about five minutes. You'll draw a shape, animate it, steer it with the keyboard and share the result. You need a Codetoy account to save, so [sign in](/) first if you haven't.

### Create a codetoy

Open **[Create](/create)** and choose **New codetoy**. The editor opens with a starter program on the left and the live preview on the right.

Pick your language with the **AS / C# / Py** switch at the top of the editor. We recommend **AS** (AssemblyScript): it's the only language that can publish [Builds](/docs/builds) and [Discord Activities](/docs/discord).

### Draw something

Replace the starter code with this, then press **▶ Play**:

```cs
Screen.OnUpdate(() => {
    // Paint the background
    Canvas.Fill(20, 20, 30);
    Canvas.Rect(0, 0, Screen.Width, Screen.Height);

    // Draw a ball in the middle
    Canvas.Fill(255, 120, 80);
    Canvas.Circle(Screen.CenterX, Screen.CenterY, 30);
});
```

`Screen.OnUpdate()` runs every frame, about 60 times a second. Each frame you paint the background, then draw everything on top of it.

### Move it with the keyboard

Keep the ball's position in variables and change them while arrow keys are held. Multiplying by `Screen.DeltaTime` (seconds since the last frame) keeps the speed the same on every screen.

```cs
double x = 200;
double y = 200;
double speed = 300; // pixels per second

Screen.OnUpdate(() => {
    double step = speed * Screen.DeltaTime;
    if (Input.IsKeyDown("ArrowLeft"))  x -= step;
    if (Input.IsKeyDown("ArrowRight")) x += step;
    if (Input.IsKeyDown("ArrowUp"))    y -= step;
    if (Input.IsKeyDown("ArrowDown"))  y += step;

    Canvas.Fill(20, 20, 30);
    Canvas.Rect(0, 0, Screen.Width, Screen.Height);

    Canvas.Fill(255, 120, 80);
    Canvas.Circle(x, y, 30);
});
```

Click the preview so it has keyboard focus, then use the arrow keys.

### React to clicks

Events fire once per action, which makes them good for one-off things like teleporting the ball to wherever you click:

```cs
Input.OnMouseDown((int button) => {
    if (button == 0) {
        x = Input.MouseX;
        y = Input.MouseY;
    }
});
```

Add this below your existing code. See [Handling Input](/docs/input) for when to use events and when to poll.

### Save and share

Press **Save** and give your codetoy a name. Its page has a short link (like `codetoy.io/AbC123`) you can send to anyone, and others can fork it to remix your code.

## Where to go next

- [Program Structure](/docs/program-structure) — How setup code, the update loop and events fit together.
- [Drawing](/docs/drawing) — Coordinates, colors, shapes, text and transforms.
- [Builds](/docs/builds) — Turn your codetoy into a hosted, game-only page.
- [Examples](/docs/examples) — Complete programs to copy and remix.

---

<!-- https://codetoy.io/docs/languages -->
# Choosing a Language

All three languages draw with the same canvas, read the same input and run the same update loop. What differs is syntax, performance and which publishing features they support.

> **Our recommendation:** Start with **AssemblyScript**. It's fast, it reads like TypeScript, and it's the only language that can publish [Builds](/docs/builds) and [Discord Activities](/docs/discord) today.

## At a glance

| | AssemblyScript | C# | Python |
|---|---|---|---|
| **Best for** | Games you want to publish | Unity and .NET developers | Learning, math and quick sketches |
| **Syntax** | TypeScript-like, strictly typed | Modern C# 14 (top-level statements) | Python 3 |
| **Runs on** | WebAssembly (compiled) | .NET on WebAssembly | Pyodide (CPython on WebAssembly) |
| **Startup** | Instant | A few seconds the first time | A few seconds the first time |
| **Performance** | Fastest | Fast | Slower; fine for sketches |
| **[Builds](/docs/builds)** | ✅ | Not yet | Not yet |
| **[Discord Activities](/docs/discord)** | ✅ | Not yet | Not yet |
| **Share & embed** | ✅ | ✅ | ✅ |
| **Update loop** | `export function update()` | `Screen.OnUpdate(() => { })` | `def update():` |
| **Events** | `export function onKeyDown()` | `Input.OnKeyDown(...)` | `def keyDown():` |

## AssemblyScript ★ Recommended

[AssemblyScript](https://www.assemblyscript.org) is a strictly typed language with TypeScript syntax that compiles straight to WebAssembly. Programs start instantly and run fast, and the compiled `.wasm` is small. That's what makes [Builds](/docs/builds) possible.

- Familiar if you know TypeScript or JavaScript.
- Numbers have explicit types: `f64` for decimals, `i32` for integers.
- Supports **operator overloading**, which is handy for vector math.
- You define `update` and event handlers as exported functions.

Coming from TypeScript? A few things work differently. Read [Language Notes](/docs/language-notes?lang=as) and the official [AssemblyScript concepts](https://www.assemblyscript.org/concepts.html) guide.

## C#

Codetoy runs modern .NET in the browser with C# 14 language features. If you use Unity or .NET, it will feel like home: `Screen.OnUpdate` works like `Update()` and `Screen.DeltaTime` like `Time.deltaTime`.

- Use [top-level statements](https://learn.microsoft.com/en-us/dotnet/csharp/fundamentals/program-structure/top-level-statements) or a classic `Main`.
- You register the update loop and events as callbacks (lambdas).
- Not available yet: Builds, Discord, `arc`, `elapsedTime`, `frameCount` and the resize event.

See [Coming from Unity](/docs/guides/unity) for a side-by-side tour.

## Python

Python runs on [Pyodide](https://pyodide.org), so the standard library (`math`, `random` and more) is there. It's the friendliest choice for beginners and for exploring math visually.

- Define functions with the right names (`update`, `keyDown`, `mouseDown` …) and Codetoy calls them.
- Remember `global` when you assign a module-level variable inside a function.
- Slower than the compiled languages: keep per-frame work modest.
- Not available yet: Builds and Discord.

---

<!-- https://codetoy.io/docs/program-structure -->
# Program Structure

Every Codetoy program has the same three parts:

1. **Setup** is code at the top level of your file. It runs once when the program starts.
2. **The update loop** is your `Screen.OnUpdate()`. It runs every frame, about 60 times a second.
3. **Events** fire once when something happens, like a key press or a click.

```cs
// 1. Setup: runs once
double x = 0;
double speed = 200;
Console.Log("Program started");

// 2. Update loop: runs every frame
Screen.OnUpdate(() => {
    x += speed * Screen.DeltaTime;
    if (x > Screen.Width) x = 0;

    Canvas.Fill(20, 20, 30);
    Canvas.Rect(0, 0, Screen.Width, Screen.Height);
    Canvas.Fill(120, 200, 255);
    Canvas.Circle(x, Screen.CenterY, 20);
});

// 3. Events: run once per action
Input.OnKeyDown((string key) => {
    if (key == " ") speed = -speed;
});
```

## How Codetoy finds your code

In C#, you **register callbacks**. Pass a lambda to `Screen.OnUpdate` for the update loop and to `Input.OnKeyDown`, `Input.OnMouseDown` and the other `Input.On…` methods for events. Registering again replaces the previous callback.

You can use [top-level statements](https://learn.microsoft.com/en-us/dotnet/csharp/fundamentals/program-structure/top-level-statements) (as in these docs) or a classic `static void Main`. Codetoy works either way.

| | AssemblyScript | C# | Python |
|---|---|---|---|
| Every frame | `export function update(): void` | `Screen.OnUpdate(Action)` | `def update()` |
| Canvas resized | `export function resize(w: f64, h: f64): void` | Not available | `def resize(w, h)` |
| Key pressed / released | `onKeyDown(key: string)` / `onKeyUp` | `Input.OnKeyDown(Action<string>)` / `OnKeyUp` | `def keyDown(key)` / `keyUp` |
| Mouse button pressed / released | `onMouseDown(button: i32)` / `onMouseUp` | `Input.OnMouseDown(Action<int>)` / `OnMouseUp` | `def mouseDown(button)` / `mouseUp` |
| Touch started / moved | `onTouchStart(id, x, y)` / `onTouchMove` | `Input.OnTouchStart(Action<int, double, double>)` / `OnTouchMove` | `def touchStart(id, x, y)` / `touchMove` |
| Touch ended | `onTouchEnd(id: i32)` | `Input.OnTouchEnd(Action<int>)` | `def touchEnd(id)` |

All events are optional. Details for each are in the [Input API](/docs/api/input) and [Screen API](/docs/api/screen).

## Keeping state

There are no game objects or components. Your game's state is just variables at the top level of your file, read and changed by `Screen.OnUpdate()` and your events.

> **Declare variables before types:** With top-level statements, put all top-level variables and statements **above** any `class`, `struct` or `enum` declarations. A statement after a type declaration is a compile error.

## The frame lifecycle

Each frame, Codetoy:

1. Delivers any input events that happened since the last frame.
2. Calls `Screen.OnUpdate()`.
3. Shows what you drew.

The canvas is **not cleared automatically**. Anything you drew last frame is still there, so most programs start `Screen.OnUpdate()` by painting a full-screen background. Skipping that is how you get trails and paint effects. See [Drawing](/docs/drawing#clearing-the-screen).

---

<!-- https://codetoy.io/docs/drawing -->
# Drawing

Codetoy draws in **immediate mode**: nothing on screen is an object you keep around. Each frame you describe the whole picture, top to bottom, back to front. The API mirrors the HTML [canvas 2D context](https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D), simplified for games.

## Coordinates

The canvas is measured in pixels with the origin at the **top-left** corner. X grows to the right and **Y grows downward**.

```text
(0, 0) ──────────────► x
  │
  │        • (centerX, centerY)
  │
  ▼ y                 (width, height)
```

The canvas fills the preview and can change size. Read `Screen.Width`, `Screen.Height`, `Screen.CenterX` and `Screen.CenterY` every frame instead of hard-coding sizes, so your program works on phones, embeds and Discord.

## Clearing the screen

The canvas keeps whatever was drawn last frame. Start every frame by painting a full-screen rectangle, or call `Canvas.Reset()`, which clears the canvas *and* resets colors, line styles and transforms.

```cs
Screen.OnUpdate(() => {
    Canvas.Fill(15, 15, 25);                         // background color
    Canvas.Rect(0, 0, Screen.Width, Screen.Height);  // paint over last frame
    // ...draw this frame
});
```

> **Trails for free:** Paint the background with some transparency, for example `Canvas.Fill()` with alpha `0.15`, and moving shapes leave fading trails.

## Colors

Drawing uses two colors: **fill** for the inside of shapes and text, and **stroke** for outlines and lines. Both stay set until you change them.

- `Canvas.Fill()` and `Canvas.Stroke()` take red, green and blue from `0` to `255`, plus an optional alpha from `0.0` to `1.0`.
- `Canvas.FillStyle()` and `Canvas.StrokeStyle()` accept any CSS color string: `"#ff6600"`, `"tomato"`, `"hsl(200 80% 60%)"`.
- `Canvas.NoFill()` and `Canvas.NoStroke()` turn either one off.

Fill and stroke are both on when a program starts, and the default stroke is a thin black outline. Call `Canvas.NoStroke()` once at the top of `Screen.OnUpdate()` for flat shapes. Setting a color with `Canvas.Fill()` or `Canvas.Stroke()` turns that one back on.

```cs
Canvas.Fill(255, 100, 0);          // opaque orange
Canvas.Fill(0, 150, 255, 0.5);     // half-transparent blue
Canvas.FillStyle("hsl(140 70% 55%)");

Canvas.Stroke(255, 255, 255);
Canvas.LineWidth(3);
Canvas.NoFill();                   // outline only
Canvas.Circle(200, 200, 50);
```

## Shapes

| Shape | Function | Notes |
|---|---|---|
| Rectangle | `Canvas.Rect()` | `x, y` is the top-left corner. An optional fifth argument rounds the corners. |
| Circle | `Canvas.Circle()` | `x, y` is the center. |
| Ellipse | `Canvas.Ellipse()` | `x, y` is the center. `w, h` are the horizontal and vertical radii. |
| Line | `Canvas.Line()` | Drawn with the stroke color and line width. |
| Triangle | `Canvas.Triangle()` | Three corner points. |
| Polygon | `Canvas.Polygon()` | A flat list of points: `[x1, y1, x2, y2, …]`. |
| Arc | _(not available in C#)_ | Part of a circle, from a start angle to an end angle, in radians. |

Every signature is in the [Canvas API](/docs/api/canvas).

## Text

Set a font with `Canvas.Font()`, then draw with `Canvas.Text()`. Text uses the fill color, and `x, y` is the **top-left corner** of the text. `Canvas.MeasureText()` returns a string's width in the current font, which is how you center text:

```cs
Canvas.Font("Arial", 32, "bold");
string label = "Game Over";
Canvas.Fill(255, 255, 255);
Canvas.Text(label, Screen.CenterX - Canvas.MeasureText(label) / 2, Screen.CenterY);
```

## Transforms

`Canvas.Translate()`, `Canvas.Rotate()` and `Canvas.Scale()` move the coordinate system for everything drawn after them. Wrap them in `Canvas.Push()` and `Canvas.Pop()` so they only affect what's in between. `Canvas.Push()` saves the colors, line settings and transform, and `Canvas.Pop()` restores them. It doesn't save whether `Canvas.NoFill()` or `Canvas.NoStroke()` is on.

```cs
double angle = 0;

Screen.OnUpdate(() => {
    angle += Screen.DeltaTime;

    Canvas.Push();
    Canvas.Translate(Screen.CenterX, Screen.CenterY);  // origin is now the center
    Canvas.Rotate(angle);                              // spin over time (radians)
    Canvas.Fill(255, 200, 60);
    Canvas.Rect(-40, -40, 80, 80);                     // a square centered on the origin
    Canvas.Pop();                                      // back to normal
});
```

Transforms combine in order. Translate first, then rotate, to spin something around its own center. `Canvas.ResetTransform()` drops all transforms without touching colors.

## Custom paths

For curves and arbitrary shapes, build a path and then fill or stroke it:

```cs
Canvas.BeginPath();
Canvas.MoveTo(100, 200);
Canvas.QuadraticCurveTo(200, 60, 300, 200);   // control point, end point
Canvas.BezierCurveTo(330, 260, 70, 260, 100, 200);
Canvas.ClosePath();

Canvas.Fill(80, 160, 255);
Canvas.FillPath();
Canvas.Stroke(255, 255, 255);
Canvas.StrokePath();
```

## Performance tips

- A few hundred to a thousand shapes per frame is comfortable. Watch `Screen.FPS` if things slow down.
- Avoid creating new arrays or lists every frame. Reuse them.
- Static backgrounds still need repainting every frame, so keep them simple.

---

<!-- https://codetoy.io/docs/animation -->
# Animation & Time

Animation means changing a value a little every frame. The catch is that frames aren't always the same length: a 120 Hz screen calls `Screen.OnUpdate()` twice as often as a 60 Hz one, and a busy frame can take longer.

## Use delta time

`Screen.DeltaTime` is the number of **seconds since the last frame**, usually about `0.016`. Multiply speeds by it so they mean "per second" instead of "per frame":

```cs
double x = 0;
double speed = 300; // pixels per second

Screen.OnUpdate(() => {
    x += 5;                          // ✗ speed depends on the frame rate
    x += speed * Screen.DeltaTime;   // ✓ 300 px/s everywhere
});
```

The same goes for anything that changes over time: rotation (radians per second), fading (alpha per second) and timers.

## Velocity and bouncing

Store a velocity, add it to the position each frame, and flip it when you hit a wall:

```cs
double x = 100, y = 100;
double vx = 220, vy = 160;
const double r = 20;

Screen.OnUpdate(() => {
    double dt = Screen.DeltaTime;
    x += vx * dt;
    y += vy * dt;

    if (x < r || x > Screen.Width - r) vx = -vx;
    if (y < r || y > Screen.Height - r) vy = -vy;

    Canvas.Fill(20, 20, 30);
    Canvas.Rect(0, 0, Screen.Width, Screen.Height);
    Canvas.Fill(100, 200, 255);
    Canvas.Circle(x, y, r);
});
```

Add gravity by increasing `vy` a little every frame (`vy += 900 * dt`).

## Elapsed time and waves

_(not available in C#)_ is the total number of seconds since the program started. Feed it to `Math.Sin()` or `Math.Cos()` for smooth back-and-forth motion, pulsing and orbits:

```cs
// C# has no ElapsedTime yet, so add up DeltaTime yourself.
double t = 0;

Screen.OnUpdate(() => {
    t += Screen.DeltaTime;
    double pulse = 40 + Math.Sin(t * 3) * 15;            // radius between 25 and 55
    double orbitX = Screen.CenterX + Math.Cos(t) * 120;
    double orbitY = Screen.CenterY + Math.Sin(t) * 120;
    Canvas.Circle(orbitX, orbitY, pulse);
});
```

## Timers

To do something every N seconds, count down with delta time:

```cs
double spawnTimer = 0;

Screen.OnUpdate(() => {
    spawnTimer -= Screen.DeltaTime;
    if (spawnTimer <= 0) {
        spawnTimer = 1.5;   // seconds until the next spawn
        // spawn an enemy...
    }
});
```

## Easing toward a target

For smooth following (cameras, cursors, UI), move a fraction of the remaining distance each frame:

```cs
double k = 1.0 - Math.Exp(-10.0 * Screen.DeltaTime);   // frame-rate independent smoothing
x += (Input.MouseX - x) * k;
y += (Input.MouseY - y) * k;
```

Higher numbers than `10` follow more tightly; lower numbers feel floatier.

---

<!-- https://codetoy.io/docs/input -->
# Handling Input

There are two ways to read input, and most games use both:

- **Polling** asks "is this held right now?" inside `Screen.OnUpdate()`. Use it for continuous things like movement, aiming and holding to charge.
- **Events** say "this just happened" once per press. Use them for one-off actions like jumping, shooting, menus and toggles.

| You want to… | Use |
|---|---|
| Move while an arrow key is held | `Input.IsKeyDown()` in `Screen.OnUpdate()` |
| Jump once when Space is pressed | `Input.OnKeyDown()` |
| Paint while the mouse button is held | `Input.IsMouseDown()` in `Screen.OnUpdate()` |
| Place a block on click | `Input.OnMouseDown()` |
| Follow a finger | `Input.TouchX()` / `Input.TouchY()` in `Screen.OnUpdate()` |
| React when a finger lands | `Input.OnTouchStart()` |

## Keyboard

Keys are named like the browser's [`KeyboardEvent.key`](https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/key/Key_Values): `"a"`, `"A"` (with Shift), `"ArrowLeft"`, `" "` (Space), `"Enter"`, `"Shift"`, `"Escape"`.

```cs
double x = 200;
bool jumping = false;

Screen.OnUpdate(() => {
    // Polling: smooth movement while held
    double step = 250 * Screen.DeltaTime;
    if (Input.IsKeyDown("a") || Input.IsKeyDown("ArrowLeft"))  x -= step;
    if (Input.IsKeyDown("d") || Input.IsKeyDown("ArrowRight")) x += step;
});

// Event: fires once per press
Input.OnKeyDown((string key) => {
    if (key == " ") jumping = true;
});
```

> **Letter case matters:** With Shift or Caps Lock on, pressing **A** reports `"A"`, not `"a"`. Check both if that matters to your game.

## Mouse

`Input.MouseX` and `Input.MouseY` are the pointer's position in canvas pixels. Buttons are numbered `0` (left), `1` (middle) and `2` (right).

```cs
Screen.OnUpdate(() => {
    // Hold the left button to paint
    if (Input.IsMouseDown(0)) {
        Canvas.Fill(255, 120, 60);
        Canvas.Circle(Input.MouseX, Input.MouseY, 12);
    }
});

Input.OnMouseDown((int button) => {
    Console.Log($"Clicked button {button}");
});
```

## Touch

On phones and tablets every finger gets an `id` that stays the same until it lifts. Touch events give you the id and position. Use `Input.TouchCount()`, `Input.IsTouchDown()`, `Input.TouchX()` and `Input.TouchY()` to poll.

```cs
Input.OnTouchStart((int id, double x, double y) => {
    Console.Log($"Finger {id} down at {x}, {y}");
});

Screen.OnUpdate(() => {
    if (Input.IsTouchDown()) {          // any finger down?
        Canvas.Fill(120, 255, 160);
    }
});
```

`Input.TouchX()` and `Input.TouchY()` return `-1` for an id that isn't down. There's a full multi-touch example on the [Examples](/docs/examples#multi-touch-paint) page.

## Supporting mouse and touch

To keep a game playable everywhere, treat a tap like a click. Handle both `Input.OnMouseDown()` and `Input.OnTouchStart()` and call the same function from each. Also keep important buttons large, since fingers are less precise than a cursor.

> **Keyboard focus:** Keyboard events only reach your codetoy after the preview has focus. If keys don't respond, click the canvas once. Embeds and Discord work the same way.

---

<!-- https://codetoy.io/docs/language-notes -->
# Language Notes

## 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.

```cs
// ✓ 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](/docs/builds) and [Discord Activities](/docs/discord) also need AssemblyScript for now.

---

<!-- https://codetoy.io/docs/builds -->
# Builds

When you share a codetoy normally, people see your code and the preview side by side. A **build** is just the game: your compiled WebAssembly captured at a moment in time, hosted at its own address on `codetoy.dev`.

```text
https://<build-id>.codetoy.dev/
```

Each build gets its own URL, and **a build never changes**. Keep editing your codetoy as much as you like: existing builds keep running exactly the version you captured. When you're ready to ship an update, capture a new build.

> **Builds require AssemblyScript:** Builds are made from the compiled `.wasm`, which today only AssemblyScript produces. For C# and Python codetoys the Builds panel shows *“Only available for AssemblyScript projects.”*

## What builds are for

- **Share a clean, playable game.** No editor, no code, the game fills the whole page.
- **[Discord Activities](/docs/discord).** Discord loads your game from its build URL.
- **[Embedding](/docs/embedding#embed-just-the-game)** a game-only iframe on your own site.
- **Versioning.** Each build is a labeled checkpoint with a message and release notes, so you can keep a known-good version live while you experiment.

## Create a build

You can only create builds for **your own, saved** codetoys.

### Open the Builds panel

Open your codetoy in the editor and press **▶ Play** to make sure the latest code compiles and runs. Then click the **Publish** button (the box icon) in the tab bar above the code, next to **Docs**.

### Click New Build

Write a **commit message** saying what changed, for example *"Add double jump and fix wall clipping"*. It must be **11 to 200 characters**.

Optionally add **release notes** (up to 2,000 characters): what's new, known issues, controls.

### Capture & Save

Codetoy captures what the preview is currently running (the compiled `build.wasm` and its `instantiate.js` loader), uploads it, and adds the build to the top of the list.

> **Run before you capture:** A build captures the **last version you ran**, not unsaved code in the editor. Press **▶ Play** right before **Capture & Save** so the build includes your latest changes.

## Open and share a build

Each build in the list shows its address, like `3f9c2a1e.codetoy.dev`. That's shortened for display; the link points to the full address with the complete build id:

```text
https://3f9c2a1e-7b4d-4c1a-9e8f-2d6b5a0c4e71.codetoy.dev/
```

Click the address to open the build in a new tab, or right-click it and choose **Copy Link** to share it. Anyone with the link can play. They don't need an account and never see your code.

## Updating a build

Builds are immutable, so "updating" means capturing a new one:

1. Make your changes and press **▶ Play**.
2. Capture a new build with a message describing the change.
3. Share the **new** build's URL. Anywhere you used the old one (a Discord URL mapping, an embed, a link in a post) needs the new URL too.

The old build keeps working until you delete it, so people mid-game aren't interrupted.

## Download build files

Each build has two download buttons:

| File | What it is |
|---|---|
| `build.wasm` | Your game, compiled to WebAssembly. |
| `instantiate.js` | The loader that connects the `.wasm` to Codetoy's runtime (canvas, input, time). |

Downloads are only available to the build's owner. They're useful for keeping an archive of releases.

> **Self-hosting:** `codetoy.dev` serves your build together with Codetoy's runtime, which provides the canvas, input and timing. The downloaded files need that runtime to run, so hosting them yourself isn't officially supported yet. For now, link to or [embed](/docs/embedding#embed-just-the-game) the build URL instead.

## Delete a build

Click the trash icon on a build and type your codetoy's name to confirm. Deleting is **permanent**. The build URL stops working immediately for everyone, including any Discord Activity or embed that uses it.

## Limits and details

| | |
|---|---|
| Language | AssemblyScript only |
| Who can create | The codetoy's owner, on a saved codetoy |
| Commit message | 11–200 characters, required |
| Release notes | Up to 2,000 characters, optional |
| Visibility | Anyone with the URL can play |
| URL format | `https://<build-id>.codetoy.dev/` |
| Contents | Compiled `build.wasm` + `instantiate.js` (your source code isn't included) |

## Troubleshooting

**The Publish button doesn't appear.** It only shows on codetoys you own, after they're saved. Forks of other people's codetoys are yours once you save them.

**"Only available for AssemblyScript projects."** Builds need AssemblyScript. Create a new codetoy with the **AS** language and move your code over.

**"Message must be more than 10 characters."** Commit messages need at least 11 characters. Describe what changed.

**"Could not get build. Request timed out."** The preview isn't running a compiled program. Press **▶ Play**, wait for it to start, then try again.

**My build shows an old version.** You captured before running your latest code. Press **▶ Play**, then capture a new build.

## Next steps

- [Discord Activities](/docs/discord) — Run your build inside Discord voice calls and DMs.
- [Embedding](/docs/embedding) — Put a codetoy or a build on your own website.

---

<!-- https://codetoy.io/docs/discord -->
# Discord Activities

Discord Activities are games and apps that run inside Discord, launched from a voice channel or DM. Any AssemblyScript codetoy can become one: Discord loads your [build](/docs/builds) URL, and the game runs without any changes to your code.

<div class="dcm not-prose" data-pagefind-ignore aria-hidden="true">
<div class="dcm-top">
<svg viewBox="0 0 24 24" class="dcm-ico"><path fill="currentColor" d="M12 3a1 1 0 0 0-1.6-.8L5.7 6H3a1 1 0 0 0-1 1v10a1 1 0 0 0 1 1h2.7l4.7 3.8A1 1 0 0 0 12 21V3Zm5.3 3.3a1 1 0 0 1 1.4 0 8 8 0 0 1 0 11.4 1 1 0 1 1-1.4-1.4 6 6 0 0 0 0-8.6 1 1 0 0 1 0-1.4Zm-2.8 2.8a1 1 0 0 1 1.4 0 4 4 0 0 1 0 5.8 1 1 0 0 1-1.4-1.4 2 2 0 0 0 0-3 1 1 0 0 1 0-1.4Z"/></svg>
<span class="dcm-channel">game-night</span>
<span class="dcm-divider"></span>
<span class="dcm-appicon"></span>
<span class="dcm-appname">Sky Hopper</span>
<span class="dcm-tag">APP</span>
<span class="dcm-spacer"></span>
<span class="dcm-count"><svg viewBox="0 0 24 24" class="dcm-ico"><path fill="currentColor" d="M9 11a4 4 0 1 0 0-8 4 4 0 0 0 0 8Zm-7 9a7 7 0 0 1 14 0v1H2v-1Zm15.5-9.2a3.5 3.5 0 1 0-1-6.8 6 6 0 0 1 0 6.1c.3.4.6.6 1 .7ZM18 21h4v-1a6 6 0 0 0-4.5-5.8A8.9 8.9 0 0 1 18 20v1Z"/></svg>4</span>
</div>
<div class="dcm-stage">
<div class="dcm-game">
<span class="dcm-cloud dcm-cloud-a"></span><span class="dcm-cloud dcm-cloud-b"></span>
<div class="dcm-pipes"><span class="dcm-pipe dcm-pipe-1"><i></i><b></b></span><span class="dcm-pipe dcm-pipe-2"><i></i><b></b></span><span class="dcm-pipe dcm-pipe-3"><i></i><b></b></span></div>
<span class="dcm-bird"><span class="dcm-eye"></span><span class="dcm-beak"></span></span>
<span class="dcm-score">12</span>
<span class="dcm-ground"></span>
</div>
<span class="dcm-url">3f9c2a1e.codetoy.dev</span>
</div>
<div class="dcm-bar">
<div class="dcm-users">
<span class="dcm-av dcm-speaking" style="--av:#5865f2">AL</span><span class="dcm-av" style="--av:#eb459e">MV</span><span class="dcm-av" style="--av:#23a559">JK</span><span class="dcm-av" style="--av:#f0b232">PX</span>
</div>
<div class="dcm-controls">
<span class="dcm-btn"><svg viewBox="0 0 24 24" class="dcm-ico"><path fill="currentColor" d="M12 2a4 4 0 0 0-4 4v6a4 4 0 0 0 8 0V6a4 4 0 0 0-4-4Zm-7 9a1 1 0 0 1 1 1 6 6 0 0 0 12 0 1 1 0 1 1 2 0 8 8 0 0 1-7 7.9V22h-2v-2.1A8 8 0 0 1 4 12a1 1 0 0 1 1-1Z"/></svg></span>
<span class="dcm-btn"><svg viewBox="0 0 24 24" class="dcm-ico"><path fill="currentColor" d="M4 6a2 2 0 0 0-2 2v8a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2v-2.2l4.4 2.9A1 1 0 0 0 22 16V8a1 1 0 0 0-1.6-.8L16 10.2V8a2 2 0 0 0-2-2H4Z"/></svg></span>
<span class="dcm-btn"><svg viewBox="0 0 24 24" class="dcm-ico"><path fill="currentColor" d="M3 4a2 2 0 0 0-2 2v10a2 2 0 0 0 2 2h7v2H7v2h10v-2h-3v-2h7a2 2 0 0 0 2-2V6a2 2 0 0 0-2-2H3Zm9 3 4 4h-3v4h-2v-4H8l4-4Z"/></svg></span>
<span class="dcm-btn dcm-active"><svg viewBox="0 0 24 24" class="dcm-ico"><path fill="currentColor" d="M20.7 3.3c-3.8-.5-7.5.9-10.2 4L8.6 9.5 5 9.9a1 1 0 0 0-.6.3L2.3 12.3l4 1.4 4 4 1.4 4 2.1-2.1a1 1 0 0 0 .3-.6l.4-3.6 2.2-1.9c3.1-2.7 4.5-6.4 4-10.2ZM15 11a2 2 0 1 1 0-4 2 2 0 0 1 0 4ZM6 16c-1.5.5-2.5 2.2-3 5 2.8-.5 4.5-1.5 5-3l-2-2Z"/></svg></span>
<span class="dcm-btn dcm-leave"><svg viewBox="0 0 24 24" class="dcm-ico"><path fill="currentColor" d="M21.7 13.4c-.2-.5-2.3-1.6-2.7-1.7-.4-.2-.7-.3-1 .2l-1.2 1.3c-.3.3-.5.3-.9.1A10.4 10.4 0 0 1 10.7 8c-.2-.4 0-.6.2-.8l.8-1c.2-.3.3-.6.2-.9L10.6 2.6c-.3-.7-.6-.6-.9-.6H9a1.6 1.6 0 0 0-1.2.6A5 5 0 0 0 6.3 6.3c0 2.2 1.6 4.3 1.8 4.6.2.3 3.1 4.8 7.6 6.7 3.8 1.5 4.5 1.2 5.3 1.1.9-.1 2.6-1.1 3-2.1.3-1.1.3-2 .2-2.1-.2-.2-.4-.3-.9-.5Z" transform="rotate(135 12 12)"/></svg></span>
</div>
<div class="dcm-right"><span class="dcm-btn dcm-ghost"><svg viewBox="0 0 24 24" class="dcm-ico"><path fill="currentColor" d="M4 4h6v2H6v4H4V4Zm10 0h6v6h-2V6h-4V4ZM4 14h2v4h4v2H4v-6Zm14 4v-4h2v6h-6v-2h4Z"/></svg></span></div>
</div>
</div>

> **Single player for now:** Everyone in the call can launch the Activity, but each player runs their own copy of the game. Multiplayer, with a way to send messages between players, is planned. [Join the Discord](https://discord.gg/tTquzrtNgN) to hear when it ships.

## Before you start

You need:

- An **AssemblyScript** codetoy. Builds and Activities don't support other languages yet.
- A **[build](/docs/builds)** of it and its URL, like `https://3f9c2a1e-….codetoy.dev/`.
- A Discord account. Setup is easiest in the [Discord desktop app](https://discord.com/download); Activities also run on mobile.

## Set up your Activity

### Create a build

In the editor, open the **Publish** panel, press **▶ Play**, then **New Build → Capture & Save**. Right-click the new build's address and copy the link. The [Builds guide](/docs/builds#create-a-build) has the details.

### Turn on Developer Mode in Discord

In Discord, open **User Settings → Advanced** and turn on **Developer Mode**. This lets you launch Activities that aren't published yet.

### Create a Discord application

Go to the Discord Developer Portal and [create a new application](https://discord.com/developers/applications?new_application=true). The name you choose is what shows up in Discord's Activity list.

### Point the URL mapping at your build

In your application, open **Activities → URL Mappings**. Under **Root Mapping**, set the **Target** to your build's host, without `https://` or a trailing slash:

```text
3f9c2a1e-7b4d-4c1a-9e8f-2d6b5a0c4e71.codetoy.dev
```

Save your changes.

### Enable Activities

Open **Activities → Settings**, turn on **Enable Activities**, and save.

### Launch it

Restart Discord so it picks up the new app. Then, in a DM or a server with **fewer than 25 members**, open the **Activities** launcher (the rocket button in a voice call or DM), find your app, and click **Launch**.

## Shipping updates

A build never changes, so when you update your game:

1. Capture a new build in Codetoy.
2. In the Developer Portal, replace the **Root Mapping** target with the new build's host.

Players get the new version the next time they launch the Activity.

## Inviting testers and going public

Until your app is published, only you (and testers you add) can launch it. Discord's [Activities documentation](https://docs.discord.com/developers/activities/overview) covers adding test users, setting your app's icon and cover art, and making the Activity available to everyone.

## Tips for Activity-friendly games

- **Size to the window.** Activities run at many sizes, from a tiny picture-in-picture tile to fullscreen on desktop and portrait on phones. Always read `Screen.Width` and `Screen.Height`; never assume a fixed canvas.
- **Support touch.** Lots of people play on their phones. Handle `Input.OnTouchStart()` as well as clicks. See [Handling Input](/docs/input#supporting-mouse-and-touch).
- **Ask for a click first.** Keyboard input needs focus, so a "Tap to start" screen helps.
- **Keep it light.** Discord runs alongside your game, so a steady frame rate matters more than detail.

## Troubleshooting

**My app doesn't show up in the Activities launcher.** Check that Developer Mode is on, Activities are enabled for the app, and you've restarted Discord. The server must have fewer than 25 members.

**The Activity opens to a blank or error screen.** Check the URL mapping target: just the host (`<build-id>.codetoy.dev`), no `https://`, no path. Open `https://<build-id>.codetoy.dev/` in a browser to confirm the build loads.

**It's still showing an old version.** Builds are immutable, so update the mapping to the new build's host, then relaunch the Activity.

**My C# or Python game doesn't work.** Activities need a build, and builds are AssemblyScript-only for now. See [Choosing a Language](/docs/languages).

---

<!-- https://codetoy.io/docs/embedding -->
# Embedding

There are two ways to embed:

| | Embed the codetoy | Embed a build |
|---|---|---|
| Shows | Code editor + live preview | Just the game, full frame |
| URL | `https://codetoy.io/<id>` | `https://<build-id>.codetoy.dev/` |
| Updates | Always the latest saved code | Fixed to one captured version |
| Languages | All | AssemblyScript |
| Good for | Tutorials, explanations, "try it" demos | Showing off a finished game |

## Embed the codetoy

Every codetoy has a short link: open it and copy the id from the address bar (`codetoy.io/codetoys/EZxvFO` → `EZxvFO`). Then drop it into an iframe:

```html
<iframe
  src="https://codetoy.io/EZxvFO"
  title="My codetoy"
  style="width: 100%; max-width: 720px; aspect-ratio: 4 / 3; border: 0; border-radius: 12px;"
  allow="fullscreen; clipboard-write"
  loading="lazy"
></iframe>
```

When Codetoy detects it's inside an iframe, it hides parts of the interface that don't make sense in an embed. Visitors can edit and run the code right there, but their changes aren't saved to your codetoy.

> **Note:** Only codetoys other people can open can be embedded. If an embed shows an error for logged-out visitors, check your codetoy's visibility.

## Embed just the game

For a clean, game-only embed, use a [build](/docs/builds) URL:

```html
<iframe
  src="https://3f9c2a1e-7b4d-4c1a-9e8f-2d6b5a0c4e71.codetoy.dev/"
  title="Sky Hopper"
  style="width: 100%; aspect-ratio: 16 / 9; border: 0; border-radius: 12px; background: #000;"
  allow="fullscreen; autoplay"
  loading="lazy"
></iframe>
```

The game fills the iframe and resizes with it, so your code's `Screen.Width` and `Screen.Height` always match the frame. A build is fixed to the version you captured. To update the embed, capture a new build and change the `src`.

## Making embeds responsive

Use `width: 100%` with an `aspect-ratio` so the embed scales with the page. If you need a fixed size, set explicit `width` and `height` instead. Codetoy adapts either way.

```html
<div style="max-width: 800px; margin: 0 auto;">
  <iframe
    src="https://codetoy.io/EZxvFO"
    title="My codetoy"
    style="display: block; width: 100%; aspect-ratio: 16 / 10; border: 0;"
    loading="lazy"
  ></iframe>
</div>
```

## Keyboard input in embeds

Browsers only send keyboard events to an iframe after someone clicks it. If your codetoy uses the keyboard, show a "Click to play" message until the first click or tap.

## Live example

<iframe src="https://codetoy.io/EZxvFO" title="Embedded codetoy example" style="width: 100%; aspect-ratio: 4 / 3; border: 0; border-radius: 12px;" loading="lazy" allow="fullscreen; clipboard-write"></iframe>

---

<!-- https://codetoy.io/docs/api/canvas -->
# Canvas

```cs
// Canvas is a global static class; no using needed.
Canvas.Fill(255, 0, 0);
```

All coordinates and sizes are in pixels, with `(0, 0)` at the top-left and Y pointing down. Colors use `0–255` for red, green and blue and `0.0–1.0` for alpha. New to drawing in Codetoy? Start with the [Drawing](/docs/drawing) guide.

## State

### reset

Clears the canvas and resets every drawing setting (colors, line styles and transforms) to the defaults. Fill and stroke are both turned back on.

```cs
Canvas.Reset()
```

### push / pop

`Canvas.Push()` saves the current drawing state (fill and stroke colors, line settings and transform). `Canvas.Pop()` restores the most recently pushed state. Calls nest, so every `Canvas.Push()` needs a matching `Canvas.Pop()`.

```cs
Canvas.Push()
Canvas.Pop()
```

```cs
Canvas.Push();
Canvas.Translate(100, 100);
Canvas.Rotate(Math.PI / 4);
Canvas.Fill(255, 0, 0);
Canvas.Rect(-20, -20, 40, 40);
Canvas.Pop();   // transform and fill color are back to what they were
```

## Color

### fill

Sets the color used to fill shapes and text, and turns fill on.

```cs
Canvas.Fill(double r, double g, double b, double a = 1.0)
```

| Parameter | Description |
|---|---|
| `r`, `g`, `b` | Red, green and blue, `0`–`255`. |
| `a` | Alpha (opacity), `0.0` (invisible) to `1.0` (opaque). Optional. |

### stroke

Sets the color used for outlines and lines, and turns stroke on. The default stroke is black.

```cs
Canvas.Stroke(double r, double g, double b, double a = 1.0)
```

### fillStyle / strokeStyle

Like `Canvas.Fill()` and `Canvas.Stroke()`, but take any [CSS color](https://developer.mozilla.org/en-US/docs/Web/CSS/color_value): hex, named colors, `rgb()`, `hsl()` and so on.

```cs
Canvas.FillStyle(string color)
Canvas.StrokeStyle(string color)

Canvas.FillStyle("#ff6600");
Canvas.StrokeStyle("hsl(200 80% 60% / 0.5)");
```

### noFill / noStroke

Turn off filling or outlining for the shapes that follow. Setting a color again with `Canvas.Fill()`/`Canvas.FillStyle()` or `Canvas.Stroke()`/`Canvas.StrokeStyle()` turns it back on.

```cs
Canvas.NoFill()
Canvas.NoStroke()
```

## Lines

### lineWidth

Sets the thickness of strokes in pixels. The default is `1`.

```cs
Canvas.LineWidth(double width)
```

### lineCap / lineJoin / lineMiterLimit

Control how line ends and corners look. They work like the canvas [`lineCap`](https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/lineCap), [`lineJoin`](https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/lineJoin) and [`miterLimit`](https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/miterLimit) properties.

```cs
Canvas.LineCap(string cap)        // "butt" | "round" | "square"
Canvas.LineJoin(string join)      // "miter" | "round" | "bevel"
Canvas.LineMiterLimit(double limit)
```

## Shapes

Shapes are filled with the fill color and outlined with the stroke color, unless `Canvas.NoFill()` or `Canvas.NoStroke()` is on.

### rect

Draws a rectangle with its top-left corner at `(x, y)`. Pass `r` to round the corners.

```cs
Canvas.Rect(double x, double y, double w, double h, double r = 0.0)
```

### circle

Draws a circle centered at `(x, y)`.

```cs
Canvas.Circle(double x, double y, double radius)
```

### ellipse

Draws an ellipse centered at `(x, y)`. `w` and `h` are the horizontal and vertical **radii** (half the full width and height).

```cs
Canvas.Ellipse(double x, double y, double w, double h)
```

### line

Draws a straight line using the stroke color and `Canvas.LineWidth()`. Lines are never filled.

```cs
Canvas.Line(double x1, double y1, double x2, double y2)
```

### triangle

Draws a triangle through three points.

```cs
Canvas.Triangle(double x1, double y1, double x2, double y2, double x3, double y3)
```

### polygon

Draws a closed shape through any number of points, passed as one flat list: `[x1, y1, x2, y2, …]`.

```cs
Canvas.Polygon(double[] points)

// a pentagon
var pts = new double[10];
for (int i = 0; i < 5; i++) {
    double a = i / 5.0 * 2 * Math.PI - Math.PI / 2;
    pts[i * 2] = 200 + Math.Cos(a) * 60;
    pts[i * 2 + 1] = 200 + Math.Sin(a) * 60;
}
Canvas.Polygon(pts);
```

### arc

Draws part of a circle centered at `(x, y)`, from `startAngle` to `endAngle` in radians. `0` points right and angles increase clockwise. The ends are joined with a straight line, so a filled arc is a circular segment (not a pie slice).

_Not available in C#._

## Transforms

Transforms change the coordinate system for everything drawn after them. They stack, and `Canvas.Push()`/`Canvas.Pop()` save and restore them.

### translate

Moves the origin by `(x, y)`.

```cs
Canvas.Translate(double x, double y)
```

### rotate

Rotates clockwise around the current origin by `radians`. Use `Canvas.Translate()` first to rotate around a shape's center.

```cs
Canvas.Rotate(double radians)
```

### scale

Scales drawing by `x` horizontally and `y` vertically. Negative values flip.

```cs
Canvas.Scale(double x, double y)
```

### resetTransform

Removes all transforms without touching colors or line settings.

```cs
Canvas.ResetTransform()
```

## Paths

Paths let you draw any outline: straight segments and curves. Start with `Canvas.BeginPath()`, add segments, then draw with `Canvas.FillPath()` and/or `Canvas.StrokePath()`. Paths use the current fill and stroke colors and ignore `Canvas.NoFill()`/`Canvas.NoStroke()`.

```cs
Canvas.BeginPath()
Canvas.MoveTo(double x, double y)
Canvas.LineTo(double x, double y)
Canvas.QuadraticCurveTo(double cpx, double cpy, double x, double y)
Canvas.BezierCurveTo(double cp1x, double cp1y, double cp2x, double cp2y, double x, double y)
Canvas.ClosePath()
Canvas.FillPath()
Canvas.StrokePath()
```

| Function | Description |
|---|---|
| `Canvas.BeginPath()` | Starts a new, empty path. |
| `Canvas.MoveTo()` | Moves the pen to `(x, y)` without drawing. |
| `Canvas.LineTo()` | Adds a straight segment to `(x, y)`. |
| `Canvas.QuadraticCurveTo()` | Adds a curve bent toward one control point. |
| `Canvas.BezierCurveTo()` | Adds a curve shaped by two control points. |
| `Canvas.ClosePath()` | Adds a segment back to the start of the path. |
| `Canvas.FillPath()` | Fills the path with the fill color. |
| `Canvas.StrokePath()` | Outlines the path with the stroke color. |

## Text

### font

Sets the font for `Canvas.Text()` and `Canvas.MeasureText()`. `family` is any CSS font family available in the browser (`"Arial"`, `"monospace"`, `"Georgia"` …), `size` is in pixels, and `weight` is a CSS weight like `"bold"` or `"600"`.

```cs
Canvas.Font(string family, double size, string weight = "normal")
```

### text

Draws a string with the fill color. `(x, y)` is the **top-left** corner of the text.

```cs
Canvas.Text(string content, double x, double y)
```

### measureText

Returns how wide `content` would be, in pixels, with the current font. Use it to center or right-align text.

```cs
Canvas.MeasureText(string content) // → double

Canvas.Font("Arial", 24, "bold");
double w = Canvas.MeasureText("Hello");
Canvas.Text("Hello", Screen.CenterX - w / 2, 20);
```

---

<!-- https://codetoy.io/docs/api/input -->
# Input

```cs
// Input is a global static class; no using needed.
Input.OnKeyDown((string key) => { });
```

For when to poll and when to use events, see the [Handling Input](/docs/input) guide.

## Keyboard

### isKeyDown

Returns `true` while `key` is held down. `key` uses the browser's [`KeyboardEvent.key`](https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/key/Key_Values) names: `"a"`, `"ArrowUp"`, `" "`, `"Enter"`, `"Shift"`.

```cs
Input.IsKeyDown(string key) // → bool
```

### onKeyDown / onKeyUp

Called once when a key is pressed or released.

```cs
Input.OnKeyDown((string key) => {
    if (key == " ") Jump();
});

Input.OnKeyUp((string key) => { });
```

## Mouse

### mouseX / mouseY

The pointer's position in canvas pixels, updated as the mouse moves.

```cs
Input.MouseX // double field
Input.MouseY // double field
```

### isMouseDown

Returns `true` while `button` is held: `0` left, `1` middle, `2` right.

```cs
Input.IsMouseDown(int button) // → bool
```

### onMouseDown / onMouseUp

Called once when a mouse button is pressed or released.

```cs
Input.OnMouseDown((int button) => {
    if (button == 0) Shoot(Input.MouseX, Input.MouseY);
});

Input.OnMouseUp((int button) => { });
```

## Touch

Each finger on the screen has an `id` that stays the same from touch start to touch end.

### touchCount

The number of fingers currently on the screen.

```cs
Input.TouchCount() // → int
```

### isTouchDown

With no argument, returns `true` if any finger is down. With an `id`, returns whether that finger is still down.

```cs
Input.IsTouchDown(int id = -1) // → bool
```

### touchX / touchY

The current position of finger `id`, or `-1` if it isn't down.

```cs
Input.TouchX(int id) // → double
Input.TouchY(int id) // → double
```

### onTouchStart / onTouchMove / onTouchEnd

Called when a finger lands, moves or lifts. Positions are in canvas pixels.

```cs
Input.OnTouchStart((int id, double x, double y) => { });
Input.OnTouchMove((int id, double x, double y) => { });
Input.OnTouchEnd((int id) => { });
```

---

<!-- https://codetoy.io/docs/api/screen -->
# Screen

```cs
// Screen is a global static class; no using needed.
```

The canvas fills its container (the editor preview, an embed, a Discord window) and can resize at any time. Read these values each frame instead of storing them once.

## Size

### width / height

The canvas size in pixels.

```cs
Screen.Width  // double field
Screen.Height // double field
```

### centerX / centerY

Half the width and height: the middle of the canvas.

```cs
Screen.CenterX // double field
Screen.CenterY // double field
```

## Frames

### fps

The current frames per second.

```cs
Screen.FPS // double field, updated once per second
```

### frameCount

The number of frames drawn since the program started.

_Not available in C#._

## The update loop

Codetoy calls your update function once per frame, before showing the canvas. See [Program Structure](/docs/program-structure).

```cs
Screen.OnUpdate(() => {
    // runs every frame
});
// Calling OnUpdate again replaces the previous callback.
```

## Resize event

Called whenever the canvas changes size, with the new width and height. Use it to recompute layout you cache, like a grid that fits the screen.

_Not available in C#._

> **Note:** C# has no resize callback yet. Compare `Screen.Width` and `Screen.Height` with last frame's values in `Screen.OnUpdate` if you need to react to resizes.

---

<!-- https://codetoy.io/docs/api/time -->
# Time

```cs
// Time lives on Screen in C#: Screen.DeltaTime.
```

See the [Animation & Time](/docs/animation) guide for patterns that use these.

## deltaTime

Seconds since the previous frame, typically about `0.016` at 60 FPS. Multiply speeds by it so movement is the same at any frame rate.

```cs
Screen.DeltaTime // double field

x += 200 * Screen.DeltaTime;   // 200 pixels per second
```

## elapsedTime

Total seconds since the program started. Great for waves, pulses and timers.

```cs
// Not available in C# yet. Add up DeltaTime instead:
double elapsed = 0;
Screen.OnUpdate(() => {
    elapsed += Screen.DeltaTime;
    double y = Screen.CenterY + Math.Sin(elapsed * 2) * 50;
});
```

---

<!-- https://codetoy.io/docs/api/console -->
# Console

Messages show up in the console under the editor. Errors thrown by your code show up there too.

## log

Prints a message.

```cs
Console.Log(string message)

Console.Log($"x = {x:F1}");
```

## warn

Prints a warning.

```cs
Console.Warn(string message)
```

## error

Prints an error.

```cs
Console.Error(string message)
```

## Debugging tips

- **Don't log every frame** unless you need to. At 60 FPS the console fills fast. Log in events, or every N frames.
- **Draw debug info on the canvas instead.** `Canvas.Text()` with `Screen.FPS`, positions or state is often clearer than the console.

```cs
Canvas.Fill(255, 255, 255);
Canvas.Font("monospace", 12);
Canvas.Text($"FPS {Screen.FPS:F0}", 8, 8);
Canvas.Text($"x {x:F1}", 8, 24);
```

---

<!-- https://codetoy.io/docs/api/math -->
# Math

Codetoy doesn't add its own math library. Each language's standard one is available:

```cs
// System.Math (imported automatically)
Math.Sin(x)   Math.Cos(x)   Math.Atan2(y, x)
Math.Sqrt(x)  Math.Pow(b, e)  Math.Abs(x)
Math.Floor(x) Math.Ceiling(x) Math.Round(x)
Math.Min(a, b) Math.Max(a, b) Math.Clamp(v, lo, hi)
Random.Shared.NextDouble() // 0 ≤ n < 1
Math.PI       Math.E       Math.Tau
```

## Angles are radians

Every angle in Codetoy (`Canvas.Rotate()`, _(not available in C#)_, `Math.Sin()`, `Math.Cos()`) is in **radians**. A full turn is `2π`, about 6.283. To convert degrees: `radians = degrees * π / 180`.

## Recipes

### Distance between two points

```cs
double dx = x2 - x1, dy = y2 - y1;
double dist = Math.Sqrt(dx * dx + dy * dy);
bool hit = dist < r1 + r2;   // two circles overlap
```

### Angle toward a point

```cs
double angle = Math.Atan2(Input.MouseY - y, Input.MouseX - x);
x += Math.Cos(angle) * speed * Screen.DeltaTime;
y += Math.Sin(angle) * speed * Screen.DeltaTime;
```

### Random number in a range

```cs
double RandomRange(double min, double max) => min + Random.Shared.NextDouble() * (max - min);
```

### Clamp and lerp

```cs
double clamped = Math.Clamp(v, lo, hi);
double Lerp(double a, double b, double t) => a + (b - a) * t;
```

### Rectangle overlap (AABB)

```cs
bool Overlaps(double ax, double ay, double aw, double ah, double bx, double by, double bw, double bh) =>
    ax < bx + bw && ax + aw > bx && ay < by + bh && ay + ah > by;
```

---

<!-- https://codetoy.io/docs/examples -->
# Examples

Every example is a whole program. Paste it into a new codetoy, press **▶ Play** and start changing numbers.

## Follow the cursor

A circle that chases the mouse smoothly and logs clicks.

```cs
double x = 0, y = 0;

Screen.OnUpdate(() => {
    double k = 1.0 - Math.Exp(-8.0 * Screen.DeltaTime);
    x += (Input.MouseX - x) * k;
    y += (Input.MouseY - y) * k;

    Canvas.Fill(20, 20, 30);
    Canvas.Rect(0, 0, Screen.Width, Screen.Height);
    Canvas.Fill(0, 150, 255);
    Canvas.Circle(x, y, 30);
});

Input.OnMouseDown((int button) => {
    Console.Log($"Clicked at {Input.MouseX}, {Input.MouseY}");
});
```

## Responsive grid

A grid that always fills the screen, whatever its size.

```cs
int cols = 6, rows = 4;

Screen.OnUpdate(() => {
    Canvas.NoStroke();
    Canvas.Fill(30, 30, 30);
    Canvas.Rect(0, 0, Screen.Width, Screen.Height);

    double cw = Screen.Width / cols;
    double ch = Screen.Height / rows;

    for (int row = 0; row < rows; row++) {
        for (int col = 0; col < cols; col++) {
            Canvas.Fill(80 + col * 30, 90 + row * 35, 210);
            Canvas.Rect(col * cw + 4, row * ch + 4, cw - 8, ch - 8, 8);
        }
    }
});
```

## Click to spawn

Every click adds a dot with a random size and color. The dots live in a list, since there are no game objects.

```cs
var dots = new List<(double X, double Y, double R, int Red, int Green)>();
var rng = new Random();

Input.OnMouseDown((int button) => {
    dots.Add((Input.MouseX, Input.MouseY, 6 + rng.NextDouble() * 18, rng.Next(80, 256), rng.Next(80, 256)));
});

Screen.OnUpdate(() => {
    Canvas.NoStroke();
    Canvas.Fill(15, 15, 25);
    Canvas.Rect(0, 0, Screen.Width, Screen.Height);

    foreach (var d in dots) {
        Canvas.Fill(d.Red, d.Green, 220);
        Canvas.Circle(d.X, d.Y, d.R);
    }
});
```

## Sine wave

A path that follows a moving sine wave across the screen.

```cs
double t = 0;

Screen.OnUpdate(() => {
    t += Screen.DeltaTime;
    Canvas.Fill(15, 15, 30);
    Canvas.Rect(0, 0, Screen.Width, Screen.Height);

    Canvas.Stroke(100, 200, 255);
    Canvas.LineWidth(3);
    Canvas.BeginPath();
    for (double x = 0; x <= Screen.Width; x += 4) {
        double y = Screen.CenterY + Math.Sin(x * 0.02 + t * 3) * 80;
        if (x == 0) Canvas.MoveTo(x, y);
        else Canvas.LineTo(x, y);
    }
    Canvas.StrokePath();
});
```

## Orbits

Transforms and `Canvas.Push()`/`Canvas.Pop()`: a moon orbits a planet that orbits a sun.

```cs
double t = 0;

Screen.OnUpdate(() => {
    t += Screen.DeltaTime;
    Canvas.NoStroke();
    Canvas.Fill(10, 10, 20);
    Canvas.Rect(0, 0, Screen.Width, Screen.Height);

    Canvas.Push();
    Canvas.Translate(Screen.CenterX, Screen.CenterY);
    Canvas.Fill(255, 200, 60);
    Canvas.Circle(0, 0, 40);          // sun

    Canvas.Rotate(t * 0.8);
    Canvas.Translate(150, 0);
    Canvas.Fill(80, 160, 255);
    Canvas.Circle(0, 0, 18);          // planet

    Canvas.Rotate(t * 3);
    Canvas.Translate(36, 0);
    Canvas.Fill(220, 220, 230);
    Canvas.Circle(0, 0, 6);           // moon
    Canvas.Pop();
});
```

## Multi-touch paint

Each finger paints in its own color, and old strokes slowly fade. Try it on a phone or tablet.

```cs
var colors = new Dictionary<int, (int R, int G)>();
var rng = new Random();

Input.OnTouchStart((int id, double x, double y) => colors[id] = (rng.Next(100, 256), rng.Next(100, 256)));
Input.OnTouchEnd((int id) => colors.Remove(id));

Screen.OnUpdate(() => {
    Canvas.NoStroke();
    Canvas.Fill(20, 20, 30, 0.08);         // translucent background leaves trails
    Canvas.Rect(0, 0, Screen.Width, Screen.Height);

    foreach (var (id, c) in colors) {
        if (!Input.IsTouchDown(id)) continue;
        Canvas.Fill(c.R, c.G, 220);
        Canvas.Circle(Input.TouchX(id), Input.TouchY(id), 24);
    }
});
```

## Catch the stars

A complete mini-game: move the paddle with the arrow keys (or A/D), catch falling stars and don't miss three.

```cs
double paddleX = 200, starX = 100, starY = -20, starSpeed = 180;
int score = 0, lives = 3;
var rng = new Random();

void DropStar() {
    starX = 20 + rng.NextDouble() * (Screen.Width - 40);
    starY = -20;
}

Input.OnKeyDown((string key) => {
    if (lives == 0 && key == " ") { score = 0; lives = 3; starSpeed = 180; DropStar(); }
});

Screen.OnUpdate(() => {
    double dt = Screen.DeltaTime, w = Screen.Width, h = Screen.Height;

    if (lives > 0) {
        if (Input.IsKeyDown("ArrowLeft") || Input.IsKeyDown("a")) paddleX -= 420 * dt;
        if (Input.IsKeyDown("ArrowRight") || Input.IsKeyDown("d")) paddleX += 420 * dt;
        paddleX = Math.Clamp(paddleX, 50, w - 50);

        starY += starSpeed * dt;
        if (starY > h - 40 && starY < h - 20 && Math.Abs(starX - paddleX) < 60) {
            score++;
            starSpeed += 15;
            DropStar();
        } else if (starY > h + 20) {
            lives--;
            DropStar();
        }
    }

    Canvas.NoStroke();
    Canvas.Fill(15, 18, 35);
    Canvas.Rect(0, 0, w, h);
    Canvas.Fill(255, 220, 80);
    Canvas.Circle(starX, starY, 12);
    Canvas.Fill(120, 200, 255);
    Canvas.Rect(paddleX - 50, h - 30, 100, 14, 7);

    Canvas.Fill(255, 255, 255);
    Canvas.Font("Arial", 18, "bold");
    Canvas.Text($"Score {score}   Lives {lives}", 12, 12);

    if (lives == 0) {
        Canvas.Font("Arial", 28, "bold");
        string msg = "Game over! Press Space";
        Canvas.Text(msg, w / 2 - Canvas.MeasureText(msg) / 2, h / 2 - 14);
    }
});
```

> **Make it a Discord game:** The AssemblyScript version of *Catch the stars* is ready to publish. Capture a [build](/docs/builds) and follow the [Discord Activities](/docs/discord) guide to play it with friends.

---

<!-- https://codetoy.io/docs/guides/unity -->
# Coming from Unity

If you know Unity, you already know most of Codetoy. Think of it as **one `MonoBehaviour` with `Update()` and `OnDrawGizmos()`, running in the browser**: no scenes, prefabs or inspector, and instant iteration.

It's not a Unity replacement. It's a place to prototype a mechanic in five minutes, explore some math, or share a runnable idea with a link, then take it back to Unity.

> **Which language?:** **C#** will feel like home, and every snippet here works in it. Switch to **AssemblyScript** in the sidebar if you want to publish your prototype as a [build](/docs/builds) or [Discord Activity](/docs/discord); the concepts are identical.

## The mental model

| Unity | Codetoy |
|---|---|
| GameObjects and components | Plain variables and classes in one file |
| Scene hierarchy | None. You draw everything yourself. |
| Renderer components draw for you | **Immediate mode**: you draw every frame |
| Camera clears the screen | You clear it (paint a background) |
| World units, Y up | Pixels, origin top-left, **Y down** (like UI) |
| Physics engine | Write your own (it's simple for 2D) |

## The game loop

```cs title="Unity"
void Update() {
    transform.position += velocity * Time.deltaTime;
}
```

```cs
double x = 0;
double speed = 150;

Screen.OnUpdate(() => {
    x += speed * Screen.DeltaTime;
    Canvas.Circle(x, Screen.CenterY, 20);
});
```

`Screen.OnUpdate()` runs once per frame like `Update()`, and `Screen.DeltaTime` is `Time.deltaTime`. There's one loop for the whole program rather than one per component.

## Drawing instead of instantiating

In Unity you create objects once and the engine renders them. In Codetoy nothing exists unless you draw it **this frame**, which is closer to `OnDrawGizmos()` or immediate-mode GUI.

```cs title="Unity"
Instantiate(circlePrefab, position, Quaternion.identity);
```

```cs
Screen.OnUpdate(() => {
    Canvas.Fill(30, 30, 30);
    Canvas.Rect(0, 0, Screen.Width, Screen.Height);   // clear: Unity does this for you
    Canvas.Circle(x, y, 30);                          // draw it every frame
});
```

To have "many objects", keep a list and draw each item in a loop. See [Spawning without GameObjects](#spawning-without-gameobjects).

## Cheat sheet

| Unity | Codetoy |
|---|---|
| `Update()` | `Screen.OnUpdate()` |
| `Time.deltaTime` | `Screen.DeltaTime` |
| `Time.time` | _(not available in C#)_ |
| `Input.mousePosition` | `Input.MouseX`, `Input.MouseY` |
| `Input.GetMouseButton(0)` | `Input.IsMouseDown()` |
| `Input.GetMouseButtonDown(0)` | `Input.OnMouseDown()` |
| `Input.GetKey(KeyCode.A)` | `Input.IsKeyDown()` with `"a"` |
| `Input.GetKeyDown(KeyCode.Space)` | `Input.OnKeyDown()` with `" "` |
| `Screen.width` / `Screen.height` | `Screen.Width` / `Screen.Height` |
| `Debug.Log` / `LogWarning` / `LogError` | `Console.Log()` / `Console.Warn()` / `Console.Error()` |
| `Gizmos.DrawWireSphere` | `Canvas.NoFill()` + `Canvas.Circle()` |
| `Mathf.Sin`, `Mathf.Atan2` | `Math.Sin()`, `Math.Atan2()` |
| `Random.value` | `Random.Shared.NextDouble()` |

## Input: polling and events

```cs title="Unity"
if (Input.GetKey(KeyCode.W)) y += speed * Time.deltaTime;
if (Input.GetKeyDown(KeyCode.Space)) Jump();
```

```cs
Screen.OnUpdate(() => {
    if (Input.IsKeyDown("w")) y -= speed * Screen.DeltaTime;   // Y is down!
});

Input.OnKeyDown((string key) => {
    if (key == " ") Jump();
});
```

Keys use browser names (`"a"`, `"ArrowUp"`, `" "`), not `KeyCode`. See the [Input API](/docs/api/input).

## State without components

There's no inspector or serialization. Treat the top of your file like a component's fields:

```cs
double playerX = 200;
double playerY = 200;
int health = 100;
double angle = 0;
```

Classes, structs, records, LINQ and generics all work. With top-level statements, declare your variables **above** any type declarations. See [Language Notes](/docs/language-notes?lang=csharp).

## Spawning without GameObjects

```cs title="Unity"
void OnMouseDown() { Instantiate(bulletPrefab, transform.position, transform.rotation); }
```

```cs
var bullets = new List<(double X, double Y)>();

Input.OnMouseDown((int button) => bullets.Add((Input.MouseX, Input.MouseY)));

Screen.OnUpdate(() => {
    Canvas.Fill(20, 20, 30);
    Canvas.Rect(0, 0, Screen.Width, Screen.Height);
    Canvas.Fill(255, 220, 80);
    for (int i = 0; i < bullets.Count; i++) {
        var b = bullets[i];
        b.Y -= 400 * Screen.DeltaTime;
        bullets[i] = b;
        Canvas.Circle(b.X, b.Y, 5);
    }
    bullets.RemoveAll(b => b.Y < -10);   // "Destroy" off-screen bullets
});
```

## Debugging

`Console.Log()`, `Console.Warn()` and `Console.Error()` print to the console under the editor, like `Debug.Log`. For per-frame values, a debug overlay drawn with `Canvas.Text()` is easier to read than a flood of logs:

```cs
Canvas.Fill(255, 80, 80);
Canvas.Font("monospace", 12);
Canvas.Text($"FPS {Screen.FPS:F0}  pos {playerX:F1}, {playerY:F1}", 10, 10);
```

## Codetoy or Unity?

**Reach for Codetoy to:** prototype a mechanic in minutes, visualize vectors and easing, teach a concept with something runnable, or share an idea as a link.

**Move to Unity when you need:** 3D, physics, an asset pipeline, animation tools, multiple scenes, or console and mobile builds.

Ready for a bigger example? [Catch the stars](/docs/examples#catch-the-stars) is a complete mini-game in every language.

---

<!-- https://codetoy.io/docs/guides/roblox -->
# Coming from Roblox

Roblox and Codetoy both give you a frame loop, input events and a scripting-first workflow. The big difference is rendering: Roblox renders the Instances you create, and Codetoy has **no Instances at all**. You paint the screen yourself, every frame.

Think of Codetoy as a **single `LocalScript` that owns the whole game** and draws onto a 2D canvas. It's a sketchbook for mechanics, math and ideas, with nothing to install and no Studio to open.

> **Which language?:** If you write **typed Luau**, you'll find **AssemblyScript** comfortable: it's TypeScript-style syntax with real types, and it's the language that can publish your game as a [Discord Activity](/docs/discord). Every example here also works in C# and Python. Pick in the sidebar.

## The mental model

| Roblox | Codetoy |
|---|---|
| `Workspace`, `Part`, `Model` | Nothing persists. You draw shapes each frame. |
| Physics engine | Movement and collisions are your code |
| Studs, 3D camera | Pixels, 2D, origin top-left, **Y down** |
| Many Scripts and LocalScripts | One file |
| `IntValue`, attributes | Plain variables |
| Services (`RunService`, `UserInputService`) | `Screen.OnUpdate()`, `Input.IsKeyDown()`, `Input.OnKeyDown()` … |

## The game loop

```lua title="Roblox (Luau)"
local RunService = game:GetService("RunService")
local x, speed = 0, 150

RunService.RenderStepped:Connect(function(dt)
    x += speed * dt
end)
```

```cs
double x = 0;
double speed = 150;

Screen.OnUpdate(() => {
    x += speed * Screen.DeltaTime;
    Canvas.Circle(x, Screen.CenterY, 20);
});
```

`Screen.OnUpdate()` is your `RenderStepped` connection and `Screen.DeltaTime` is `dt`. Logic and drawing happen in the same place.

## Parts vs. drawing

```lua title="Roblox (Luau)"
local part = Instance.new("Part")
part.Position = Vector3.new(0, 5, 0)
part.Parent = workspace
```

```cs
Screen.OnUpdate(() => {
    Canvas.Fill(30, 30, 30);
    Canvas.Rect(0, 0, Screen.Width, Screen.Height);   // clear the last frame
    Canvas.Fill(160, 160, 170);
    Canvas.Rect(100, 100, 50, 50);                    // "the part", drawn this frame
});
```

> **Clear the screen yourself:** Roblox redraws the world every frame for you; Codetoy doesn't. If you don't paint a background (or call `Canvas.Reset()`), each frame draws on top of the last. That's great for trails, and confusing the first time.

## Cheat sheet

| Roblox | Codetoy |
|---|---|
| `RunService.RenderStepped` / `Heartbeat` | `Screen.OnUpdate()` |
| `dt` | `Screen.DeltaTime` |
| `os.clock()` / `time()` | _(not available in C#)_ |
| `UserInputService:IsKeyDown(Enum.KeyCode.W)` | `Input.IsKeyDown()` with `"w"` |
| `InputBegan` (keyboard) | `Input.OnKeyDown()` |
| `UserInputService:GetMouseLocation()` | `Input.MouseX`, `Input.MouseY` |
| `MouseButton1Down` | `Input.OnMouseDown()` with button `0` |
| `TouchStarted` / `TouchEnded` | `Input.OnTouchStart()` / `Input.OnTouchEnd()` |
| `print` / `warn` | `Console.Log()` / `Console.Warn()` |
| `math.sin`, `math.random` | `Math.Sin()`, `Random.Shared.NextDouble()` |
| `workspace.CurrentCamera.ViewportSize` | `Screen.Width`, `Screen.Height` |

## WASD movement

```lua title="Roblox (Luau)"
local UIS = game:GetService("UserInputService")
RunService.RenderStepped:Connect(function(dt)
    if UIS:IsKeyDown(Enum.KeyCode.W) then y -= speed * dt end
end)
```

```cs
double x = 200, y = 200, speed = 300;

Screen.OnUpdate(() => {
    double step = speed * Screen.DeltaTime;
    if (Input.IsKeyDown("w")) y -= step;
    if (Input.IsKeyDown("s")) y += step;
    if (Input.IsKeyDown("a")) x -= step;
    if (Input.IsKeyDown("d")) x += step;

    Canvas.Fill(20, 20, 30);
    Canvas.Rect(0, 0, Screen.Width, Screen.Height);
    Canvas.Fill(0, 170, 255);
    Canvas.Circle(x, y, 20);
});
```

Note that up is **minus** Y on a canvas.

## Spawning things

Where you'd `Instance.new` and parent to `workspace`, keep a list and draw everything in it:

```lua title="Roblox (Luau)"
mouse.Button1Down:Connect(function()
    local p = Instance.new("Part")
    p.Position = mouse.Hit.Position
    p.Parent = workspace
end)
```

```cs
var points = new List<(double X, double Y)>();

Input.OnMouseDown((int button) => points.Add((Input.MouseX, Input.MouseY)));

Screen.OnUpdate(() => {
    Canvas.Fill(20, 20, 30);
    Canvas.Rect(0, 0, Screen.Width, Screen.Height);
    Canvas.Fill(255, 170, 60);
    foreach (var p in points) Canvas.Circle(p.X, p.Y, 15);
});
```

## Coming from Luau syntax

- `local x = 0` becomes `double x = 0;`, or `var` when the type is obvious.
- Tables become `List<T>`, `Dictionary<K, V>`, tuples or a `class`/`record`.
- `if … then … end` becomes `if (…) { … }`; `~=` is `!=`; `..` is `+` or `$"interpolation {x}"`.
- Collections are **0-indexed**.

## Codetoy or Roblox?

**Use Codetoy to:** prototype a mechanic without Studio, learn graphics and math, test logic fast, or share a runnable demo with a link. AssemblyScript games can even run in [Discord](/docs/discord).

**Use Roblox when you need:** 3D worlds, built-in physics and multiplayer, avatars, assets and the Roblox audience.

---

<!-- https://codetoy.io/docs/guides/web -->
# Coming from the Web

If you've drawn on an HTML `<canvas>`, Codetoy will feel familiar. Its drawing API is a trimmed-down `CanvasRenderingContext2D`, and its loop is `requestAnimationFrame` with the boilerplate removed. There's no HTML, no bundler, no `getContext`, and no resize handling to write.

> **Use AssemblyScript:** **AssemblyScript** is TypeScript syntax compiled to WebAssembly, so you can read it immediately. It's also the language behind [Builds](/docs/builds) and [Discord Activities](/docs/discord). The snippets below follow the sidebar's language; leave it on AssemblyScript for the closest match.

## What you don't have to write

```js title="Browser canvas"
const canvas = document.querySelector("canvas")
const ctx = canvas.getContext("2d")

function resize() {
  canvas.width = innerWidth * devicePixelRatio
  canvas.height = innerHeight * devicePixelRatio
  ctx.scale(devicePixelRatio, devicePixelRatio)
}
addEventListener("resize", resize)
resize()

let last = performance.now()
function frame(now) {
  const dt = (now - last) / 1000
  last = now
  ctx.fillStyle = "#14141e"
  ctx.fillRect(0, 0, innerWidth, innerHeight)
  ctx.fillStyle = "#64b4ff"
  ctx.beginPath()
  ctx.arc(mouse.x, mouse.y, 24, 0, Math.PI * 2)
  ctx.fill()
  requestAnimationFrame(frame)
}
requestAnimationFrame(frame)
```

```cs
Screen.OnUpdate(() => {
    Canvas.Fill(20, 20, 30);
    Canvas.Rect(0, 0, Screen.Width, Screen.Height);
    Canvas.Fill(100, 180, 255);
    Canvas.Circle(Input.MouseX, Input.MouseY, 24);
});
```

Codetoy handles high-DPI scaling, resizing, the frame loop and timing for you.

## Canvas API mapping

| `CanvasRenderingContext2D` | Codetoy |
|---|---|
| `ctx.fillStyle = "…"` | `Canvas.FillStyle()`, or `Canvas.Fill()` with RGB(A) |
| `ctx.strokeStyle = "…"` | `Canvas.StrokeStyle()`, or `Canvas.Stroke()` |
| `ctx.fillRect` / `ctx.roundRect` | `Canvas.Rect()` (fifth argument is the corner radius) |
| `ctx.arc(…, 0, 2π)` + `fill()` | `Canvas.Circle()` |
| `ctx.ellipse` | `Canvas.Ellipse()` |
| `ctx.moveTo` + `lineTo` + `stroke()` | `Canvas.Line()` |
| `ctx.lineWidth = n` | `Canvas.LineWidth()` |
| `ctx.lineCap`, `lineJoin`, `miterLimit` | `Canvas.LineCap()`, `Canvas.LineJoin()`, `Canvas.LineMiterLimit()` |
| `ctx.save()` / `ctx.restore()` | `Canvas.Push()` / `Canvas.Pop()` |
| `ctx.translate` / `rotate` / `scale` | `Canvas.Translate()` / `Canvas.Rotate()` / `Canvas.Scale()` |
| `ctx.resetTransform()` | `Canvas.ResetTransform()` |
| `ctx.beginPath` … `fill()` / `stroke()` | `Canvas.BeginPath()` … `Canvas.FillPath()` / `Canvas.StrokePath()` |
| `ctx.font = "bold 24px Arial"` | `Canvas.Font()` with `"Arial", 24, "bold"` |
| `ctx.fillText` | `Canvas.Text()` (top-left aligned) |
| `ctx.measureText(s).width` | `Canvas.MeasureText()` |
| `ctx.reset()` | `Canvas.Reset()` |

Two differences to know:

- **Shapes fill and stroke in one call.** `Canvas.Rect()`, `Canvas.Circle()` and friends use the current fill *and* stroke (a thin black outline by default). Call `Canvas.NoStroke()` or `Canvas.NoFill()` to turn either off.
- **Text is drawn from its top-left corner**, as if `textBaseline = "top"`.

## Events

| DOM | Codetoy |
|---|---|
| `requestAnimationFrame` loop | `Screen.OnUpdate()` |
| `keydown` / `keyup` | `Input.OnKeyDown()` / `Input.OnKeyUp()` (same `event.key` names) |
| Tracking pressed keys in a `Set` | `Input.IsKeyDown()` |
| `mousemove` → `clientX/Y` | `Input.MouseX`, `Input.MouseY` (already in canvas pixels) |
| `mousedown` / `mouseup` | `Input.OnMouseDown()` / `Input.OnMouseUp()` (same `event.button` numbers) |
| `touchstart` / `touchmove` / `touchend` | `Input.OnTouchStart()` / `Input.OnTouchMove()` / `Input.OnTouchEnd()` |
| `resize` | _(not available in C#)_ |
| `console.log` | `Console.Log()` |

## From prototype to published

Because AssemblyScript compiles to a compact `.wasm`, finished games can be captured as a [build](/docs/builds): a hosted, game-only page at `https://<build-id>.codetoy.dev/`. You can [embed](/docs/embedding#embed-just-the-game) it on your own site or run it as a [Discord Activity](/docs/discord).

---

<!-- https://codetoy.io/docs/guides/new-to-coding -->
# New to Coding

Welcome! Codetoy is a great place to practice because you see the result of every line you write, instantly, as pictures and motion. You only need a handful of ideas to make something fun.

## Pick a language

If you're brand new, **Python** reads the most like plain English. If you'd like to share your games in Discord later, choose **AssemblyScript**. It looks a little more technical but works the same way. Choose one in the sidebar and every example on this site will follow it.

## The five ideas you need

### 1. Instructions run top to bottom

A program is a list of instructions. The computer runs them in order.

### 2. Functions do things

`circle(200, 150, 40)` *calls* a function: "draw a circle at x = 200, y = 150 with radius 40". The numbers in the parentheses are its *arguments*.

### 3. Variables remember things

A variable is a named box that holds a value. Change the value and everything that uses it changes too.

```cs
double size = 40;
Canvas.Circle(200, 150, size);
```

### 4. `if` makes decisions

Run code only when something is true, like when a key is held down.

### 5. Loops repeat

A `for` loop repeats code, for example to draw a row of ten circles.

## Your first program

Create a [new codetoy](/create), choose your language, paste this in and press **▶ Play**. Then try changing the numbers. What happens if you make `40` bigger?

```cs
Screen.OnUpdate(() => {
    // a dark background
    Canvas.Fill(20, 20, 40);
    Canvas.Rect(0, 0, Screen.Width, Screen.Height);

    // a row of circles
    for (int i = 0; i < 10; i++) {
        Canvas.Fill(80 + i * 17, 150, 255);
        Canvas.Circle(60 + i * 60, 150, 20);
    }

    // a circle that follows your mouse, and grows while you hold the button
    double size = 40;
    if (Input.IsMouseDown(0)) {
        size = 80;
    }
    Canvas.Fill(255, 200, 80);
    Canvas.Circle(Input.MouseX, Input.MouseY, size);
});
```

Every line of that program uses one of the five ideas above. Text after `//` (or `#` in Python) is a *comment*: a note for humans that the computer ignores.

## When something goes wrong

Errors show up in the console under the editor, with a line number. Read the first error and look at that line. Common culprits are a missing bracket, a typo in a name, or a capital letter where it shouldn't be. Every programmer sees errors all day, so they're part of the process, not a sign you're doing it wrong.

## Keep learning

- [Quickstart](/docs/quickstart) — Build a ball you can steer with the keyboard.
- [Examples](/docs/examples) — Complete programs to copy, run and change.
- [Khan Academy: Intro to programming](https://www.khanacademy.org/computing/computer-programming/programming/drawing-basics/pt/making-drawings-with-code) — Free lessons on drawing with code. Great alongside Codetoy.
- [Codetoy Discord](https://discord.gg/tTquzrtNgN) — Ask questions and share what you make.
