# Codetoy documentation (AssemblyScript)

<!-- 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).

```ts
import { fill, rect, circle } from "codetoy/canvas"
import * as screen from "codetoy/screen"
import * as input from "codetoy/input"

export function update(): void {
  fill(20, 20, 30)
  rect(0, 0, screen.width(), screen.height())

  fill(100, 180, 255)
  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 `export function update()` 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**:

```ts
import { fill, rect, circle } from "codetoy/canvas"
import * as screen from "codetoy/screen"

export function update(): void {
  // Paint the background
  fill(20, 20, 30)
  rect(0, 0, screen.width(), screen.height())

  // Draw a ball in the middle
  fill(255, 120, 80)
  circle(screen.centerX(), screen.centerY(), 30)
}
```

`export function update()` 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 `deltaTime()` (seconds since the last frame) keeps the speed the same on every screen.

```ts
import { fill, rect, circle } from "codetoy/canvas"
import * as screen from "codetoy/screen"
import * as input from "codetoy/input"
import { deltaTime } from "codetoy/time"

let x: f64 = 200
let y: f64 = 200
const speed: f64 = 300 // pixels per second

export function update(): void {
  const step = speed * 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

  fill(20, 20, 30)
  rect(0, 0, screen.width(), screen.height())

  fill(255, 120, 80)
  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:

```ts
export function onMouseDown(button: i32): void {
  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 `export function update()`. It runs every frame, about 60 times a second.
3. **Events** fire once when something happens, like a key press or a click.

```ts
import { fill, rect, circle } from "codetoy/canvas"
import * as screen from "codetoy/screen"
import { deltaTime } from "codetoy/time"

// 1. Setup: runs once
let x: f64 = 0
let speed: f64 = 200
console.log("Program started")

// 2. Update loop: runs every frame
export function update(): void {
  x += speed * deltaTime()
  if (x > screen.width()) x = 0

  fill(20, 20, 30)
  rect(0, 0, screen.width(), screen.height())
  fill(120, 200, 255)
  circle(x, screen.centerY(), 20)
}

// 3. Events: run once per action
export function onKeyDown(key: string): void {
  if (key == " ") speed = -speed
}
```

## How Codetoy finds your code

In AssemblyScript, Codetoy calls functions you **export** from your file by name. An unexported `update` is never called, so don't forget `export`.

| | 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 `export function update()` and your events.

Give top-level variables an explicit type when the inferred one isn't what you want. `let x = 0` is an integer (`i32`), so write `let x: f64 = 0` for a position that moves by fractions of a pixel.

## The frame lifecycle

Each frame, Codetoy:

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

The canvas is **not cleared automatically**. Anything you drew last frame is still there, so most programs start `export function update()` 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 `reset()`, which clears the canvas *and* resets colors, line styles and transforms.

```ts
export function update(): void {
  fill(15, 15, 25)                             // background color
  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 `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.

- `fill()` and `stroke()` take red, green and blue from `0` to `255`, plus an optional alpha from `0.0` to `1.0`.
- `fillStyle()` and `strokeStyle()` accept any CSS color string: `"#ff6600"`, `"tomato"`, `"hsl(200 80% 60%)"`.
- `noFill()` and `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 `noStroke()` once at the top of `export function update()` for flat shapes. Setting a color with `fill()` or `stroke()` turns that one back on.

```ts
fill(255, 100, 0)          // opaque orange
fill(0, 150, 255, 0.5)     // half-transparent blue
fillStyle("hsl(140 70% 55%)")

stroke(255, 255, 255)
lineWidth(3)
noFill()                   // outline only
circle(200, 200, 50)
```

## Shapes

| Shape | Function | Notes |
|---|---|---|
| Rectangle | `rect()` | `x, y` is the top-left corner. An optional fifth argument rounds the corners. |
| Circle | `circle()` | `x, y` is the center. |
| Ellipse | `ellipse()` | `x, y` is the center. `w, h` are the horizontal and vertical radii. |
| Line | `line()` | Drawn with the stroke color and line width. |
| Triangle | `triangle()` | Three corner points. |
| Polygon | `polygon()` | A flat list of points: `[x1, y1, x2, y2, …]`. |
| Arc | `arc()` | 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 `font()`, then draw with `text()`. Text uses the fill color, and `x, y` is the **top-left corner** of the text. `measureText()` returns a string's width in the current font, which is how you center text:

```ts
font("Arial", 32, "bold")
const label = "Game Over"
fill(255, 255, 255)
text(label, screen.centerX() - measureText(label) / 2, screen.centerY())
```

## Transforms

`translate()`, `rotate()` and `scale()` move the coordinate system for everything drawn after them. Wrap them in `push()` and `pop()` so they only affect what's in between. `push()` saves the colors, line settings and transform, and `pop()` restores them. It doesn't save whether `noFill()` or `noStroke()` is on.

```ts
push()
translate(screen.centerX(), screen.centerY())  // origin is now the center
rotate(elapsedTime())                          // spin over time (radians)
fill(255, 200, 60)
rect(-40, -40, 80, 80)                         // a square centered on the origin
pop()                                          // back to normal
```

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

## Custom paths

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

```ts
beginPath()
moveTo(100, 200)
quadraticCurveTo(200, 60, 300, 200)   // control point, end point
bezierCurveTo(330, 260, 70, 260, 100, 200)
closePath()

fill(80, 160, 255)
fillPath()
stroke(255, 255, 255)
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 `export function update()` twice as often as a 60 Hz one, and a busy frame can take longer.

## Use delta time

`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":

```ts
let x: f64 = 0
const speed: f64 = 300 // pixels per second

export function update(): void {
  x += 5                      // ✗ speed depends on the frame rate
  x += speed * 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:

```ts
import { fill, rect, circle } from "codetoy/canvas"
import * as screen from "codetoy/screen"
import { deltaTime } from "codetoy/time"

let x: f64 = 100, y: f64 = 100
let vx: f64 = 220, vy: f64 = 160
const r: f64 = 20

export function update(): void {
  const dt = 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

  fill(20, 20, 30)
  rect(0, 0, screen.width(), screen.height())
  fill(100, 200, 255)
  circle(x, y, r)
}
```

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

## Elapsed time and waves

`elapsedTime()` 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:

```ts
const t = elapsedTime()
const pulse = 40 + Math.sin(t * 3) * 15             // radius between 25 and 55
const orbitX = screen.centerX() + Math.cos(t) * 120
const orbitY = screen.centerY() + Math.sin(t) * 120
circle(orbitX, orbitY, pulse)
```

## Timers

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

```ts
let spawnTimer: f64 = 0

export function update(): void {
  spawnTimer -= 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:

```ts
const k = 1.0 - Math.exp(-10.0 * 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 `export function update()`. 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 `export function update()` |
| Jump once when Space is pressed | `export function onKeyDown()` |
| Paint while the mouse button is held | `input.isMouseDown()` in `export function update()` |
| Place a block on click | `export function onMouseDown()` |
| Follow a finger | `input.touchX()` / `input.touchY()` in `export function update()` |
| React when a finger lands | `export function 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"`.

```ts
import * as input from "codetoy/input"
import { deltaTime } from "codetoy/time"

let x: f64 = 200
let jumping = false

export function update(): void {
  // Polling: smooth movement while held
  const step = 250 * deltaTime()
  if (input.isKeyDown("a") || input.isKeyDown("ArrowLeft"))  x -= step
  if (input.isKeyDown("d") || input.isKeyDown("ArrowRight")) x += step
}

// Event: fires once per press
export function onKeyDown(key: string): void {
  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).

```ts
export function update(): void {
  // Hold the left button to paint
  if (input.isMouseDown(0)) {
    fill(255, 120, 60)
    circle(input.mouseX(), input.mouseY(), 12)
  }
}

export function onMouseDown(button: i32): void {
  console.log("Clicked button " + button.toString())
}
```

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

```ts
export function onTouchStart(id: i32, x: f64, y: f64): void {
  console.log("Finger " + id.toString() + " down")
}

export function update(): void {
  if (input.isTouchDown()) {          // any finger down?
    fill(120, 255, 160)
    // Draw under the first finger that landed
    // (use the ids from onTouchStart to track several)
  }
}
```

`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 `export function onMouseDown()` and `export function 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

## Imports

Codetoy's API comes in four modules. Import only what you use, either by name or as a namespace. These docs use names for canvas and time, and namespaces for screen and input:

```ts
import { fill, rect, circle, text, font } from "codetoy/canvas"
import * as screen from "codetoy/screen"   // screen.width(), screen.centerX() ...
import * as input from "codetoy/input"     // input.mouseX(), input.isKeyDown() ...
import { deltaTime, elapsedTime } from "codetoy/time"
```

`console` and `Math` are global and need no import.

## Number types

AssemblyScript compiles to WebAssembly, so numbers have concrete types:

| Type | Use for |
|---|---|
| `f64` | Positions, speeds, angles: almost everything in the API |
| `i32` | Counters, indices, mouse buttons, touch ids |
| `bool` | Flags |

Integer literals default to `i32`. Give variables an explicit type when you mean a decimal:

```ts
let x = 0          // i32! x += 0.5 is a type error
let y: f64 = 0     // what you usually want
```

Convert between types with `as`: `(i as f64) / 5.0`, or `<i32>Math.floor(x)`.

## Strings

Join with `+` and convert numbers with `.toString()`. Template literals work too:

```ts
console.log("Score: " + score.toString())
text(`FPS: ${Math.round(screen.fps())}`, 10, 10)
```

## Arrays and classes

Arrays are typed: `new Array<f64>()` or `const pts: f64[] = [0, 0, 10, 10]`. Classes work like TypeScript classes, including constructor parameter properties.

## Operator overloading

AssemblyScript lets classes define operators, which makes vector math read naturally. The editor's TypeScript checker may underline it, but it compiles and runs:

```ts
class Vec2 {
  constructor(public x: f64, public y: f64) {}

  @operator("+") add(o: Vec2): Vec2 { return new Vec2(this.x + o.x, this.y + o.y) }
  @operator("*") scale(s: f64): Vec2 { return new Vec2(this.x * s, this.y * s) }
}

let pos = new Vec2(100, 100)
const vel = new Vec2(120, 40)

export function update(): void {
  pos = pos + vel * deltaTime()
}
```

## Differences from TypeScript

- No `any`, no `undefined`, and no union types except nullable classes (`Foo | null`).
- Closures can't capture local variables. Use top-level variables or class fields.
- Annotate the return type of functions you export, e.g. `export function update(): void`.

More detail: [AssemblyScript concepts](https://www.assemblyscript.org/concepts.html) and [feature status](https://www.assemblyscript.org/status.html#language-features).

---

<!-- 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 `export function 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

```ts
import { fill, rect, circle /* … */ } from "codetoy/canvas"
// or: import * as canvas from "codetoy/canvas"
```

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.

```ts
reset(): void
```

### push / pop

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

```ts
push(): void
pop(): void
```

```ts
push()
translate(100, 100)
rotate(Math.PI / 4)
fill(255, 0, 0)
rect(-20, -20, 40, 40)
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.

```ts
fill(r: f64, g: f64, b: f64, a: f64 = 1.0): void
```

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

```ts
stroke(r: f64, g: f64, b: f64, a: f64 = 1.0): void
```

### fillStyle / strokeStyle

Like `fill()` and `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.

```ts
fillStyle(color: string): void
strokeStyle(color: string): void

fillStyle("#ff6600")
strokeStyle("hsl(200 80% 60% / 0.5)")
```

### noFill / noStroke

Turn off filling or outlining for the shapes that follow. Setting a color again with `fill()`/`fillStyle()` or `stroke()`/`strokeStyle()` turns it back on.

```ts
noFill(): void
noStroke(): void
```

## Lines

### lineWidth

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

```ts
lineWidth(width: f64): void
```

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

```ts
lineCap(cap: string): void        // "butt" | "round" | "square"
lineJoin(join: string): void      // "miter" | "round" | "bevel"
lineMiterLimit(limit: f64): void
```

## Shapes

Shapes are filled with the fill color and outlined with the stroke color, unless `noFill()` or `noStroke()` is on.

### rect

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

```ts
rect(x: f64, y: f64, width: f64, height: f64, r: f64 = 0.0): void
```

### circle

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

```ts
circle(x: f64, y: f64, radius: f64): void
```

### ellipse

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

```ts
ellipse(x: f64, y: f64, w: f64, h: f64): void
```

### line

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

```ts
line(x1: f64, y1: f64, x2: f64, y2: f64): void
```

### triangle

Draws a triangle through three points.

```ts
triangle(x1: f64, y1: f64, x2: f64, y2: f64, x3: f64, y3: f64): void
```

### polygon

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

```ts
polygon(points: f64[]): void

// a pentagon
const pts = new Array<f64>()
for (let i = 0; i < 5; i++) {
  const a = (i as f64) / 5.0 * 2.0 * Math.PI - Math.PI / 2
  pts.push(200 + Math.cos(a) * 60)
  pts.push(200 + Math.sin(a) * 60)
}
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).

```ts
arc(x: f64, y: f64, radius: f64, startAngle: f64, endAngle: f64, anticlockwise: bool = false): void
```

## Transforms

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

### translate

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

```ts
translate(x: f64, y: f64): void
```

### rotate

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

```ts
rotate(radians: f64): void
```

### scale

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

```ts
scale(x: f64, y: f64): void
```

### resetTransform

Removes all transforms without touching colors or line settings.

```ts
resetTransform(): void
```

## Paths

Paths let you draw any outline: straight segments and curves. Start with `beginPath()`, add segments, then draw with `fillPath()` and/or `strokePath()`. Paths use the current fill and stroke colors and ignore `noFill()`/`noStroke()`.

```ts
beginPath(): void
moveTo(x: f64, y: f64): void
lineTo(x: f64, y: f64): void
quadraticCurveTo(cpx: f64, cpy: f64, x: f64, y: f64): void
bezierCurveTo(cp1x: f64, cp1y: f64, cp2x: f64, cp2y: f64, x: f64, y: f64): void
closePath(): void
fillPath(): void
strokePath(): void
```

| Function | Description |
|---|---|
| `beginPath()` | Starts a new, empty path. |
| `moveTo()` | Moves the pen to `(x, y)` without drawing. |
| `lineTo()` | Adds a straight segment to `(x, y)`. |
| `quadraticCurveTo()` | Adds a curve bent toward one control point. |
| `bezierCurveTo()` | Adds a curve shaped by two control points. |
| `closePath()` | Adds a segment back to the start of the path. |
| `fillPath()` | Fills the path with the fill color. |
| `strokePath()` | Outlines the path with the stroke color. |

## Text

### font

Sets the font for `text()` and `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"`.

```ts
font(family: string, size: f64, weight: string = "normal"): void
```

### text

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

```ts
text(content: string, x: f64, y: f64): void
```

### measureText

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

```ts
measureText(content: string): f64

font("Arial", 24, "bold")
const w = measureText("Hello")
text("Hello", screen.centerX() - w / 2, 20)
```

---

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

```ts
import * as input from "codetoy/input"
// Events are functions you export: onKeyDown, onMouseDown, onTouchStart, ...
```

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"`.

```ts
input.isKeyDown(key: string): bool
```

### onKeyDown / onKeyUp

Called once when a key is pressed or released.

```ts
export function onKeyDown(key: string): void {
  if (key == " ") jump()
}

export function onKeyUp(key: string): void { }
```

## Mouse

### mouseX / mouseY

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

```ts
input.mouseX(): f64
input.mouseY(): f64
```

### isMouseDown

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

```ts
input.isMouseDown(button: i32): bool
```

### onMouseDown / onMouseUp

Called once when a mouse button is pressed or released.

```ts
export function onMouseDown(button: i32): void {
  if (button == 0) shoot(input.mouseX(), input.mouseY())
}

export function onMouseUp(button: i32): void { }
```

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

```ts
input.touchCount(): i32
```

### isTouchDown

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

```ts
input.isTouchDown(id: i32 = -1): bool
```

### touchX / touchY

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

```ts
input.touchX(id: i32): f64
input.touchY(id: i32): f64
```

### onTouchStart / onTouchMove / onTouchEnd

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

```ts
export function onTouchStart(id: i32, x: f64, y: f64): void { }
export function onTouchMove(id: i32, x: f64, y: f64): void { }
export function onTouchEnd(id: i32): void { }
```

---

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

```ts
import * as screen from "codetoy/screen"
```

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.

```ts
screen.width(): f64
screen.height(): f64
```

### centerX / centerY

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

```ts
screen.centerX(): f64
screen.centerY(): f64
```

## Frames

### fps

The current frames per second.

```ts
screen.fps(): f64
```

### frameCount

The number of frames drawn since the program started.

```ts
screen.frameCount(): i32
```

## The update loop

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

```ts
export function update(): void {
  // runs every frame
}
```

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

```ts
export function resize(width: f64, height: f64): void {
  cellSize = Math.min(width, height) / 10
}
```

---

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

```ts
import { deltaTime, elapsedTime } from "codetoy/time"
```

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.

```ts
deltaTime(): f64

x += 200 * deltaTime()   // 200 pixels per second
```

## elapsedTime

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

```ts
elapsedTime(): f64

const y = screen.centerY() + Math.sin(elapsedTime() * 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.

```ts
console.log(message: string): void

console.log("x = " + x.toString())
```

## warn

Prints a warning.

```ts
console.warn(message: string): void
```

## error

Prints an error.

```ts
console.error(message: string): void
```

## 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.** `text()` with `screen.fps()`, positions or state is often clearer than the console.

```ts
fill(255, 255, 255)
font("monospace", 12)
text("FPS " + Math.round(screen.fps()).toString(), 8, 8)
text("x " + x.toString(), 8, 24)
```

---

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

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

```ts
// Global Math, like JavaScript's (all f64)
Math.sin(x)   Math.cos(x)   Math.atan2(y, x)
Math.sqrt(x)  Math.pow(b, e)  Math.abs(x)
Math.floor(x) Math.ceil(x)  Math.round(x)
Math.min(a, b) Math.max(a, b)
Math.random() // 0 ≤ n < 1
Math.PI       Math.E
```

AssemblyScript's `Math` works on `f64`. For 32-bit floats there's `Mathf` (`Mathf.sin`, …). The full list is in the [AssemblyScript Math reference](https://www.assemblyscript.org/stdlib/math.html).

## Angles are radians

Every angle in Codetoy (`rotate()`, `arc()`, `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

```ts
const dx = x2 - x1, dy = y2 - y1
const dist = Math.sqrt(dx * dx + dy * dy)
const hit = dist < r1 + r2   // two circles overlap
```

### Angle toward a point

```ts
const angle = Math.atan2(input.mouseY() - y, input.mouseX() - x)
x += Math.cos(angle) * speed * deltaTime()
y += Math.sin(angle) * speed * deltaTime()
```

### Random number in a range

```ts
function randomRange(min: f64, max: f64): f64 {
  return min + Math.random() * (max - min)
}
```

### Clamp and lerp

```ts
function clamp(v: f64, lo: f64, hi: f64): f64 { return Math.max(lo, Math.min(hi, v)) }
function lerp(a: f64, b: f64, t: f64): f64 { return a + (b - a) * t }
```

### Rectangle overlap (AABB)

```ts
function overlaps(ax: f64, ay: f64, aw: f64, ah: f64, bx: f64, by: f64, bw: f64, bh: f64): bool {
  return 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.

```ts
import { fill, rect, circle } from "codetoy/canvas"
import * as screen from "codetoy/screen"
import * as input from "codetoy/input"
import { deltaTime } from "codetoy/time"

let x: f64 = 0
let y: f64 = 0

export function update(): void {
  const k = 1.0 - Math.exp(-8.0 * deltaTime())
  x += (input.mouseX() - x) * k
  y += (input.mouseY() - y) * k

  fill(20, 20, 30)
  rect(0, 0, screen.width(), screen.height())
  fill(0, 150, 255)
  circle(x, y, 30)
}

export function onMouseDown(button: i32): void {
  console.log("Clicked at " + input.mouseX().toString() + ", " + input.mouseY().toString())
}
```

## Responsive grid

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

```ts
import { fill, rect, noStroke } from "codetoy/canvas"
import * as screen from "codetoy/screen"

const cols = 6
const rows = 4

export function update(): void {
  noStroke()
  fill(30, 30, 30)
  rect(0, 0, screen.width(), screen.height())

  const cw = screen.width() / (cols as f64)
  const ch = screen.height() / (rows as f64)

  for (let row = 0; row < rows; row++) {
    for (let col = 0; col < cols; col++) {
      fill(80 + col * 30, 90 + row * 35, 210)
      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.

```ts
import { fill, rect, circle, noStroke } from "codetoy/canvas"
import * as screen from "codetoy/screen"
import * as input from "codetoy/input"

class Dot {
  constructor(public x: f64, public y: f64, public r: f64, public hue: f64) {}
}

const dots = new Array<Dot>()

export function onMouseDown(button: i32): void {
  dots.push(new Dot(input.mouseX(), input.mouseY(), 6 + Math.random() * 18, Math.random() * 360))
}

export function update(): void {
  noStroke()
  fill(15, 15, 25)
  rect(0, 0, screen.width(), screen.height())

  for (let i = 0; i < dots.length; i++) {
    const d = dots[i]
    fill(128 + Math.cos(d.hue) * 127, 128 + Math.sin(d.hue) * 127, 200)
    circle(d.x, d.y, d.r)
  }
}
```

## Sine wave

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

```ts
import { fill, rect, stroke, lineWidth, beginPath, moveTo, lineTo, strokePath } from "codetoy/canvas"
import * as screen from "codetoy/screen"
import { elapsedTime } from "codetoy/time"

export function update(): void {
  const t = elapsedTime()
  fill(15, 15, 30)
  rect(0, 0, screen.width(), screen.height())

  stroke(100, 200, 255)
  lineWidth(3)
  beginPath()
  for (let x: f64 = 0; x <= screen.width(); x += 4) {
    const y = screen.centerY() + Math.sin(x * 0.02 + t * 3) * 80
    if (x == 0) moveTo(x, y)
    else lineTo(x, y)
  }
  strokePath()
}
```

## Orbits

Transforms and `push()`/`pop()`: a moon orbits a planet that orbits a sun.

```ts
import { fill, rect, circle, noStroke, push, pop, translate, rotate } from "codetoy/canvas"
import * as screen from "codetoy/screen"
import { elapsedTime } from "codetoy/time"

export function update(): void {
  const t = elapsedTime()
  noStroke()
  fill(10, 10, 20)
  rect(0, 0, screen.width(), screen.height())

  push()
  translate(screen.centerX(), screen.centerY())
  fill(255, 200, 60)
  circle(0, 0, 40)            // sun

  rotate(t * 0.8)
  translate(150, 0)
  fill(80, 160, 255)
  circle(0, 0, 18)            // planet

  rotate(t * 3)
  translate(36, 0)
  fill(220, 220, 230)
  circle(0, 0, 6)             // moon
  pop()
}
```

## Multi-touch paint

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

```ts
import { fill, rect, circle, noStroke } from "codetoy/canvas"
import * as screen from "codetoy/screen"
import * as input from "codetoy/input"

const ids = new Array<i32>()

export function onTouchStart(id: i32, x: f64, y: f64): void { ids.push(id) }

export function onTouchEnd(id: i32): void {
  const i = ids.indexOf(id)
  if (i >= 0) ids.splice(i, 1)
}

export function update(): void {
  noStroke()
  fill(20, 20, 30, 0.08)                 // translucent background leaves trails
  rect(0, 0, screen.width(), screen.height())

  for (let i = 0; i < ids.length; i++) {
    const id = ids[i]
    fill(120 + (id * 70) % 135, 255 - (id * 50) % 155, 200)
    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.

```ts
import { fill, rect, circle, text, font, measureText, noStroke } from "codetoy/canvas"
import * as screen from "codetoy/screen"
import * as input from "codetoy/input"
import { deltaTime } from "codetoy/time"

let paddleX: f64 = 200
let starX: f64 = 100
let starY: f64 = -20
let starSpeed: f64 = 180
let score = 0
let lives = 3

function dropStar(): void {
  starX = 20 + Math.random() * (screen.width() - 40)
  starY = -20
}

export function onKeyDown(key: string): void {
  if (lives == 0 && key == " ") { score = 0; lives = 3; starSpeed = 180; dropStar() }
}

export function update(): void {
  const dt = deltaTime()
  const 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.max(50, Math.min(w - 50, paddleX))

    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()
    }
  }

  noStroke()
  fill(15, 18, 35)
  rect(0, 0, w, h)
  fill(255, 220, 80)
  circle(starX, starY, 12)
  fill(120, 200, 255)
  rect(paddleX - 50, h - 30, 100, 14, 7)

  fill(255, 255, 255)
  font("Arial", 18, "bold")
  text("Score " + score.toString() + "   Lives " + lives.toString(), 12, 12)

  if (lives == 0) {
    font("Arial", 28, "bold")
    const msg = "Game over! Press Space"
    text(msg, w / 2 - 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;
}
```

```ts
let x: f64 = 0
const speed: f64 = 150

export function update(): void {
  x += speed * deltaTime()
  circle(x, screen.centerY(), 20)
}
```

`export function update()` runs once per frame like `Update()`, and `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);
```

```ts
export function update(): void {
  fill(30, 30, 30)
  rect(0, 0, screen.width(), screen.height())   // clear: Unity does this for you
  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()` | `export function update()` |
| `Time.deltaTime` | `deltaTime()` |
| `Time.time` | `elapsedTime()` |
| `Input.mousePosition` | `input.mouseX()`, `input.mouseY()` |
| `Input.GetMouseButton(0)` | `input.isMouseDown()` |
| `Input.GetMouseButtonDown(0)` | `export function onMouseDown()` |
| `Input.GetKey(KeyCode.A)` | `input.isKeyDown()` with `"a"` |
| `Input.GetKeyDown(KeyCode.Space)` | `export function onKeyDown()` with `" "` |
| `Screen.width` / `Screen.height` | `screen.width()` / `screen.height()` |
| `Debug.Log` / `LogWarning` / `LogError` | `console.log()` / `console.warn()` / `console.error()` |
| `Gizmos.DrawWireSphere` | `noFill()` + `circle()` |
| `Mathf.Sin`, `Mathf.Atan2` | `Math.sin()`, `Math.atan2()` |
| `Random.value` | `Math.random()` |

## Input: polling and events

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

```ts
export function update(): void {
  if (input.isKeyDown("w")) y -= speed * deltaTime()   // Y is down!
}

export function onKeyDown(key: string): void {
  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:

```ts
let playerX: f64 = 200
let playerY: f64 = 200
let health = 100
let angle: f64 = 0
```

## Spawning without GameObjects

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

```ts
class Bullet { constructor(public x: f64, public y: f64) {} }
const bullets = new Array<Bullet>()

export function onMouseDown(button: i32): void {
  bullets.push(new Bullet(input.mouseX(), input.mouseY()))
}

export function update(): void {
  fill(20, 20, 30)
  rect(0, 0, screen.width(), screen.height())
  fill(255, 220, 80)
  for (let i = 0; i < bullets.length; i++) {
    const b = bullets[i]
    b.y -= 400 * deltaTime()
    circle(b.x, b.y, 5)
  }
}
```

## 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 `text()` is easier to read than a flood of logs:

```ts
fill(255, 80, 80)
font("monospace", 12)
text("FPS " + Math.round(screen.fps()).toString(), 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`) | `export function update()`, `input.isKeyDown()`, `export function 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)
```

```ts
let x: f64 = 0
const speed: f64 = 150

export function update(): void {
  x += speed * deltaTime()
  circle(x, screen.centerY(), 20)
}
```

`export function update()` is your `RenderStepped` connection and `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
```

```ts
export function update(): void {
  fill(30, 30, 30)
  rect(0, 0, screen.width(), screen.height())   // clear the last frame
  fill(160, 160, 170)
  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 `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` | `export function update()` |
| `dt` | `deltaTime()` |
| `os.clock()` / `time()` | `elapsedTime()` |
| `UserInputService:IsKeyDown(Enum.KeyCode.W)` | `input.isKeyDown()` with `"w"` |
| `InputBegan` (keyboard) | `export function onKeyDown()` |
| `UserInputService:GetMouseLocation()` | `input.mouseX()`, `input.mouseY()` |
| `MouseButton1Down` | `export function onMouseDown()` with button `0` |
| `TouchStarted` / `TouchEnded` | `export function onTouchStart()` / `export function onTouchEnd()` |
| `print` / `warn` | `console.log()` / `console.warn()` |
| `math.sin`, `math.random` | `Math.sin()`, `Math.random()` |
| `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)
```

```ts
let x: f64 = 200, y: f64 = 200
const speed: f64 = 300

export function update(): void {
  const step = speed * 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

  fill(20, 20, 30)
  rect(0, 0, screen.width(), screen.height())
  fill(0, 170, 255)
  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)
```

```ts
const xs = new Array<f64>()
const ys = new Array<f64>()

export function onMouseDown(button: i32): void {
  xs.push(input.mouseX())
  ys.push(input.mouseY())
}

export function update(): void {
  fill(20, 20, 30)
  rect(0, 0, screen.width(), screen.height())
  fill(255, 170, 60)
  for (let i = 0; i < xs.length; i++) circle(xs[i], ys[i], 15)
}
```

## Coming from Luau syntax

- `local x = 0` becomes `let x: f64 = 0`. Annotate decimals as `f64`; plain integer literals are `i32`.
- `function f(a: number): number` becomes `function f(a: f64): f64`.
- Tables become typed `Array<T>`, `Map<K, V>` or a `class`.
- `if … then … end` becomes `if (…) { … }`; `~=` is `!=`; `..` (concatenation) is `+`.
- Arrays 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)
```

```ts
import { fill, rect, circle } from "codetoy/canvas"
import * as screen from "codetoy/screen"
import * as input from "codetoy/input"

export function update(): void {
  fill(20, 20, 30)
  rect(0, 0, screen.width(), screen.height())
  fill(100, 180, 255)
  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 = "…"` | `fillStyle()`, or `fill()` with RGB(A) |
| `ctx.strokeStyle = "…"` | `strokeStyle()`, or `stroke()` |
| `ctx.fillRect` / `ctx.roundRect` | `rect()` (fifth argument is the corner radius) |
| `ctx.arc(…, 0, 2π)` + `fill()` | `circle()` |
| `ctx.ellipse` | `ellipse()` |
| `ctx.moveTo` + `lineTo` + `stroke()` | `line()` |
| `ctx.lineWidth = n` | `lineWidth()` |
| `ctx.lineCap`, `lineJoin`, `miterLimit` | `lineCap()`, `lineJoin()`, `lineMiterLimit()` |
| `ctx.save()` / `ctx.restore()` | `push()` / `pop()` |
| `ctx.translate` / `rotate` / `scale` | `translate()` / `rotate()` / `scale()` |
| `ctx.resetTransform()` | `resetTransform()` |
| `ctx.beginPath` … `fill()` / `stroke()` | `beginPath()` … `fillPath()` / `strokePath()` |
| `ctx.font = "bold 24px Arial"` | `font()` with `"Arial", 24, "bold"` |
| `ctx.fillText` | `text()` (top-left aligned) |
| `ctx.measureText(s).width` | `measureText()` |
| `ctx.reset()` | `reset()` |

Two differences to know:

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

## Events

| DOM | Codetoy |
|---|---|
| `requestAnimationFrame` loop | `export function update()` |
| `keydown` / `keyup` | `export function onKeyDown()` / `export function 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` | `export function onMouseDown()` / `export function onMouseUp()` (same `event.button` numbers) |
| `touchstart` / `touchmove` / `touchend` | `export function onTouchStart()` / `export function onTouchMove()` / `export function onTouchEnd()` |
| `resize` | `export function resize()` |
| `console.log` | `console.log()` |

## TypeScript vs. AssemblyScript

AssemblyScript looks like TypeScript but compiles ahead of time to WebAssembly, so it's stricter:

- Numbers are concrete types: `f64` (like JS `number`), `i32`, `u8` and so on. `let x = 0` is an `i32`, so write `let x: f64 = 0`.
- No `any`, `undefined`, or union types (except nullable classes like `Enemy | null`).
- Closures can't capture local variables; use top-level variables or class fields.
- No DOM, `fetch` or `setTimeout`: everything goes through Codetoy's API.
- Bonus: **operator overloading** with `@operator("+")`.

More in [Language Notes](/docs/language-notes?lang=as) and the [AssemblyScript docs](https://www.assemblyscript.org/concepts.html).

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

```ts
let size: f64 = 40
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?

```ts
import { fill, rect, circle } from "codetoy/canvas"
import * as screen from "codetoy/screen"
import * as input from "codetoy/input"

export function update(): void {
  // a dark background
  fill(20, 20, 40)
  rect(0, 0, screen.width(), screen.height())

  // a row of circles
  for (let i = 0; i < 10; i++) {
    fill(80 + i * 17, 150, 255)
    circle(60 + i * 60, 150, 20)
  }

  // a circle that follows your mouse, and grows while you hold the button
  let size: f64 = 40
  if (input.isMouseDown(0)) {
    size = 80
  }
  fill(255, 200, 80)
  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.
