# Assets

> Import images and sounds, and use them for avatars, sounds and the UI.

Assets are the images and sounds your game uses: a texture for the ball, a
goal sound, a logo in the Menu. They live in your project folder next to your
code, and they ship inside your release.

You add an asset by importing it, just like a module. The import doesn't give
you the file's contents. It gives you a small **reference** you pass to disko.
The players' browsers download the file itself only when they need it.

```mermaid alt="Importing art/puck.png gives a reference. The game passes it to disko, for example as a disc avatar, which tells players' browsers which asset to show. The browsers download puck.png from the room when they need it."
flowchart TB
  code["import puck"] -- "reference" --> game["ball.setAvatar(puck)"]
  game -- "which asset to show" --> browser["Players' browsers"]
  room["Room"] -- "puck.png, when needed" --> browser
```

## Importing an asset

An asset is packaged only if a module imports it (see
[What goes into a release](/games/project-structure#what-goes-into-a-release)),
and only with a default import:

```ts title="src/main.ts"
import puck from "./art/puck.png";
import goal from "./sounds/goal.ogg";
```

The value you get is a frozen object such as
`{ kind: "package-asset", name: "art/puck.png" }`, where `name` is the file's
path in the project. Importing the same file twice gives the same object.

Only the default import form works. Named imports, `import * as`, and
importing a file just for its side effects are rejected
([`asset_import_form`](/errors/asset_import_form)). You may re-export one,
though: `export { default as puck } from "./art/puck.png"`.

## Using an asset

Pass the reference wherever disko accepts an asset: `disc.setAvatar` or
`player.setAvatar` for images on discs, `game.playSound` for sounds, and
`ui.image({ asset })` in the Menu or HUD.

```ts title="src/main.ts"
game.on("start", () => {
  const ball = world.createDisc({ radius: 10 });

  // An image asset as a disc avatar.
  ball.setAvatar(puck);

  game.on("crossing", () => {
    // An audio asset, positioned at the ball.
    game.playSound(goal, { source: ball });
  });
});

// Images also work in the Menu and HUD.
ui.menu(ui.image({ asset: puck, accessibleName: "Puck" }));
```

## Supported formats

| Extension       | Type         |
| --------------- | ------------ |
| `.png`          | `image/png`  |
| `.jpg`, `.jpeg` | `image/jpeg` |
| `.webp`         | `image/webp` |
| `.mp3`          | `audio/mpeg` |
| `.ogg`          | `audio/ogg`  |
| `.wav`          | `audio/wav`  |

- Extensions must be lowercase, and SVG isn't supported.
- A file's contents must match its extension: a JPEG renamed to `.png` is
  rejected ([`asset_content_mismatch`](/errors/asset_content_mismatch)).
- Images can be 1 to 4096 pixels per side
  ([`image_dimensions`](/errors/image_dimensions)), and each asset at most
  16 MiB.
