---
title: TIC-80
url: 'https://wiki.teletypegames.org/platforms/tic80'
markdown: 'https://wiki.teletypegames.org/platforms/tic80.md'
lang: en
date: '2026-03-03'
description: 'TIC-80 is a tiny fantasy computer for small games. Code, sprites, maps, sound and music are all edited inside it. Website: https://tic80.com Tools repository: https://git.teletypegames.org/build/tic80-tools Makefile A cartridge is one .lua file. To keep the code modular, we split it into many file…'
taxonomy:
  tag:
    - howto
---

# TIC-80

TIC-80 is a tiny fantasy computer for small games. Code, sprites, maps, sound and music are all edited inside it.

**Website:** https://tic80.com **Tools repository**: https://git.teletypegames.org/build/tic80-tools

---

# Makefile

A cartridge is one `.lua` file. To keep the code modular, we split it into many files and concatenate them at build time.

```text
project-root/
├── inc/
│   ├── core.lua
│   ├── player.lua
│   └── world.lua
├── impostor.inc      # build order, one file name per line
├── Makefile
└── README.md
```

`impostor.lua` is generated. Order matters: a file must come after the globals it uses.

## Targets

```sh
make build                  # concatenate inc/ files into <project>.lua
make minify                 # shrink the code, backup to <project>.original.lua
make export VERSION=1.0.0    # build + minify, then save .tic and .html.zip
make export_assets          # PALETTE/TILES/SPRITES/MAP/SFX/WAVES -> inc/meta/meta.assets.lua
make import_assets          # import assets/<type>/*.png into the cartridge
make watch                  # rebuild on change in inc/, the .inc file and assets/
make lint                   # luacheck, with line numbers mapped back to source files
make docs                   # ldoc HTML into docs/
make install_precommit_hook # .git/hooks/pre-commit runs make lint
make clean                  # remove generated files
```

`export` also copies the versioned files to unversioned names (`impostor.tic`, `impostor.html.zip`). `export_assets` keeps the graphics in version control as source code.

## VS Code

Copy `example-tasks.json` from the tools repo to `.vscode/tasks.json` and replace `impostor.lua` with your cart name. Tasks: **Run TIC80** (default, `Cmd+Shift+B`), **Build & Run TIC80**, **Export assets**, **Make build**.

## Generated artifacts

| File | Description |
|---|---|
| `<project>.lua` | Merged (and minified) source |
| `<project>.original.lua` | Pre-minification backup |
| `<project>.tic` | Cartridge |
| `<project>.html.zip` | HTML build |
| `<project>-*-docs.zip` | Documentation |
| `<project>-*-win-x64.zip` | Windows player, cart baked in |
| `<project>-*-linux-x64.zip` | Linux player, cart baked in |
| `<project>-*-mac-x64.zip` | macOS (Intel) player, cart baked in |

## Requirements

Local only: `make`, `tic80` in `PATH`, `lua`, `luacheck`, `ldoc`, `curl`, and `fswatch` for watch mode. CI installs its own tools.

---

# Pipeline

The pipeline is not in the game repo. Woodpecker asks the update server for it, and WarpEngine serves the whole config from `/build/config` (template `lib/warp_engine/ci/woodpecker/platforms/tic80/pipeline.yaml.erb`).

The repo needs three things:

```yaml
# .woodpecker.yaml
platform: tic80
```

- `name: <software>` — only when the software name differs from the repo name
- the `application_token` Woodpecker secret: a WarpEngine ApplicationToken with `update` + `upload` scopes, created in the admin

TIC-80 projects have **no `metadata.json`**. The version and the catalog metadata come from the comment header in `inc/meta/meta.header.lua`.

See the exact commands:

```sh
curl "https://teletypegames.org/build/config?platform=tic80"
```

## Steps

| Step | What it does |
|---|---|
| 1. version | the engine's shared step (since WarpEngine 1.7): the version from the `-- version:` line of `inc/meta/meta.header.lua`; on a tag a version tag has to match it; outside the repo's default branch and on a `dev-<branch>` tag `dev-<version>-<branch>`, with no version `dev-<commit>`; write `.version` |
| 2. lint | `luacheck` in the `tools` image (`ci-tools` on teletypegames.org, luacheck and ldoc preinstalled; without one, `alpine` + `luarocks install` on every run); merge `inc/` in `.inc` order with a line map; fail on any issue |
| 3. minify | concatenate and minify with `lua-minify-tic80`; keep the original for docs |
| 4. docs | `ldoc` on the pre-minification source, zipped as `<name>-<version>-docs.zip` |
| 5. export | in the `tic80pro` image: save the `.tic` cart and export `.html.zip` |
| 6. binaries | `export win / linux / mac` with the cart baked in, one zip per slug; templates are downloaded from tic80.com, so this step needs network |
| 7. upload | **on the tag only:** `POST /build/upload` per file, `X-Update-Secret` header from `application_token` |
| 8. publish | **on the tag only:** `POST /build/publish?platform=tic80` |
| 9. tag | the engine's shared step (since WarpEngine 1.9), **after a push only**: a new version in the source gets its `v<version>` tag, whose pipeline runs the steps marked *on the tag only*; a version tagged already releases nothing; a dev build moves the branch's `dev-<branch>` tag onto the commit, so the newest dev build is published. See *Versions and releases* on the [WarpEngine](https://wiki.teletypegames.org/engines/warp-engine) page |

Raising the version is the release: a push builds and tags, and the tag's pipeline uploads and publishes (WarpEngine 1.9). A push that leaves the version as it is only builds.

The builder image (`tic80pro`) and the tools image come from the update server's `ci_platforms` config, not from the repo. With `ci-tools` the lint step went from 10–15 s to 3 s and the docs step from 12–14 s to 1 s.

## Result

Linted, minified, versioned build; docs and native players attached as ReleaseAssets; the public game index updates itself. All build logic lives server-side — the repo carries only the marker and its token.

---

# Builder image

TIC-80 Pro is a commercial product, sold on **itch.io**. The source is open, so with a license you can build your own Pro binary in a clean image.

```dockerfile
FROM ubuntu:24.04

RUN apt-get update && apt-get install -y \
      build-essential cmake git \
      libsdl2-dev libpipewire-0.3-dev libwayland-dev \
      ruby-dev lua5.4 libcurl4-openssl-dev \
    && rm -rf /var/lib/apt/lists/*

RUN git clone --recursive https://github.com/nesbox/TIC-80 /opt/TIC-80
RUN cd /opt/TIC-80/build \
    && cmake -DBUILD_PRO=On -DBUILD_SDLGPU=On -DBUILD_WITH_ALL=On -DBUILD_STATIC=On .. \
    && cmake --build . --parallel

ENV PATH="/opt/TIC-80/build/bin:${PATH}"
WORKDIR /workspace
CMD ["/bin/bash"]
```

| Flag | Why |
|---|---|
| `BUILD_PRO=On` | enables the Pro features |
| `BUILD_SDLGPU=On`, `BUILD_WITH_ALL=On` | GPU support and every optional feature |
| `BUILD_STATIC=On` | one portable binary, no shared library surprises |

'; var prevLevel = 2; for (var i = 0; i < headings.length; i++) { var h = headings\[i\]; var text = h.textContent.trim(); var slug = text.toLowerCase() .replace(/\[áàâä\]/g,'a').replace(/\[éèêë\]/g,'e').replace(/\[íìîï\]/g,'i') .replace(/\[óòôöő\]/g,'o').replace(/\[úùûüű\]/g,'u') .replace(/\[^a-z0-9\]+/g, '-').replace(/^-|-$/g, ''); if (!slug) slug = 'heading-' + i; if (used\[slug\]) { slug += '-' + i; } used\[slug\] = true; h.id = slug; var level = parseInt(h.tagName.charAt(1)); var cls = level > 2 ? ' class="toc-child"' : ''; html += '- [' + text + '](#'%20+%20slug%20+%20')
'; } html += '
'; toc.innerHTML = html; // Scroll-spy: highlight current heading var links = toc.querySelectorAll('a'); var ids = \[\]; for (var j = 0; j < links.length; j++) ids.push(links\[j\].getAttribute('href').slice(1)); function updateActive() { var current = ''; for (var k = 0; k < ids.length; k++) { var el = document.getElementById(ids\[k\]); if (el && el.getBoundingClientRect().top <= 80) current = ids\[k\]; } for (var m = 0; m < links.length; m++) { links\[m\].parentNode.classList.toggle('active', links\[m\].getAttribute('href') === '#' + current); } } window.addEventListener('scroll', updateActive, { passive: true }); updateActive(); })();

---

## Navigation

- Parent: [Platforms](https://wiki.teletypegames.org/platforms.md)
- Previous: [Commodore Plus/4](https://wiki.teletypegames.org/platforms/plus4.md)
