Login

TIC-80

TIC-80 is a tiny fantasy computer designed for making, playing, and sharing small games. It provides built-in tools for code, sprites, maps, sound, and music, encouraging rapid prototyping and creative constraints.

Website: https://tic80.com Tools repository: https://git.teletype.hu/tools/tic80-tools


Makefile

This Makefile provides a simple, reproducible workflow for building TIC-80 Lua projects from multiple source files. It is designed for small indie or experimental projects where the source code is split into logical parts and then merged into a single .lua cartridge.

Overview

The workflow is based on four core ideas:

  • Source code is split into multiple Lua files inside an inc/ directory
  • A project-specific .inc file defines the build order
  • All source files are concatenated into one final .lua file
  • TIC-80 is used in CLI mode to export runnable artifacts

This approach keeps the codebase modular while remaining compatible with TIC-80's single-file cartridge model.

Project Structure

TEXT
project-root/
├── inc/
│   ├── core.lua
│   ├── player.lua
│   └── world.lua
├── impostor.inc
├── Makefile
└── README.md
  • inc/ contains all Lua source fragments
  • <project>.inc defines the order in which files are merged
  • <project>.lua is generated automatically

The .inc File

The .inc file is a plain text file listing Lua source files in build order:

TEXT
core.lua
player.lua
world.lua

The order matters. Files listed earlier are concatenated first and must define any globals used later.

Usage

Build (default)

SH
make build
  • Reads <project>.inc (e.g., impostor.inc)
  • Concatenates files from inc/
  • Produces <project>.lua (e.g., impostor.lua)

Minify

SH
make minify
  • Purpose: Compresses the generated Lua code to save space in the TIC-80 cartridge.
  • Mechanism: Downloads a minifier script (minify.lua) and uses it to process the concatenated Lua file. The original code is backed up as <project>.original.lua.

Export (TIC-80)

SH
make export VERSION=1.0.0
  • Requires a VERSION variable.
  • First runs build and minify to ensure the code is ready.
  • Loads the generated (and minified) Lua file into TIC-80 (CLI mode).
  • Saves a versioned .tic cartridge (e.g., impostor-1.0.0.tic).
  • Exports a versioned HTML build (e.g., impostor-1.0.0.html.zip).
  • Copies the versioned artifacts to unversioned names (impostor.tic, impostor.html.zip) for consistency.

Export Assets

SH
make export_assets
  • Purpose: Extracts asset sections (PALETTE, TILES, SPRITES, MAP, SFX, WAVES) from the compiled <project>.lua file.
  • Mechanism: Uses awk to directly parse the generated <project>.lua and saves the extracted data into inc/meta/meta.assets.lua. This allows visual assets to be tracked in version control as source code.

Import Assets

SH
make import_assets
  • Purpose: Automatically imports graphical assets into the TIC-80 project.
  • It iterates over asset types (tiles, sprites, sfx, music).
  • For each type, it looks for .png files in assets/<type>/.
  • It uses the tic80 --cli import command to load each asset into the cartridge.

Watch Mode

SH
make watch
  • Performs an initial build.
  • Watches the inc/ directory, the .inc file, and the assets/ directory for changes.
  • Rebuilds automatically on any change.
  • Requires fswatch to be installed.

Lint Code

SH
make lint
  • Purpose: Statically analyzes all Lua source files for issues like syntax errors and unused variables.
  • Mechanism: Concatenates source files into a temporary file, runs luacheck, and remaps line numbers back to the original source files for accurate error reporting.

Docs

SH
make docs
  • Purpose: Generates API documentation from the source code.
  • Mechanism: Uses ldoc to process the compiled <project>.lua file and outputs HTML documentation into the docs/ directory.

Install Pre-Commit Hook

SH
make install_precommit_hook
  • Purpose: Sets up a Git pre-commit hook to automatically lint the code before every commit.
  • Mechanism: Creates an executable script at .git/hooks/pre-commit that runs make lint.

Clean

SH
make clean
  • Removes generated build artifacts:
    • Versioned cartridges (<project>-*.tic)
    • Versioned HTML builds (<project>-*.html.zip)
    • The main concatenated Lua file (<project>.lua)
    • Minification backups (<project>.original.lua)

CI/CD Targets

These targets are designed for automated continuous integration (e.g., Woodpecker CI). Each target reads the version from the .version file created by ci-version.

make ci-version

  • Extracts the version string from inc/meta/meta.header.lua.
  • Appends the branch name (if not main/master) for development builds (e.g., dev-1.0.0-feature-foo).
  • Writes the version to a .version file for subsequent steps.

make ci-lint

  • Runs make lint to statically analyze the Lua source files.
  • Fails the pipeline if any issues are found.

make ci-minify

  • Runs make minify to build the project and minify the output.
  • Produces both <project>.lua (minified) and <project>.original.lua (pre-minification backup).

make ci-docs

  • Generates API documentation from the pre-minification source (<project>.original.lua) using ldoc.
  • Zips the generated docs into a versioned archive (e.g., <project>-1.0.0-docs.zip).
  • Creates an unversioned copy (<project>-docs.zip) for convenience.

make ci-export

  • Reads the version from the .version file.
  • Loads the minified Lua file into TIC-80 (CLI mode) and exports versioned .tic and .html.zip artifacts.
  • Copies versioned artifacts to unversioned names for consistency.

make ci-artifact

  • Uploads the generated .lua, .tic, .html.zip, and -docs.zip artifacts to a remote server using scp.
  • Uses sshpass for SSH authentication.
  • Connection details are configured via environment variables (DROPAREA_HOST, DROPAREA_PORT, DROPAREA_USER, DROPAREA_TARGET_PATH).

make ci-update

  • Triggers a remote update/deployment process via curl to a predefined update server.
  • Uses a secret key (UPDATE_SECRET) to authorize the request.

Generated Artifacts

File Description
<project>.lua Merged and potentially minified Lua source
<project>.original.lua Pre-minification source backup
<project>.tic TIC-80 cartridge
<project>.html.zip Packaged HTML build
<project>-*-docs.zip Versioned documentation archive
<project>-docs.zip Latest documentation archive

Requirements

  • make
  • tic80 available in PATH
  • lua (for minification)
  • luacheck (for linting)
  • ldoc (for documentation)
  • fswatch (only for watch mode)
  • sshpass and curl (for CI/CD targets)

Pipeline

This document describes the Woodpecker CI pipeline used to build, export, upload, and publish a TIC-80 game project.

Overview

The pipeline logic is almost entirely encapsulated within a Makefile, which is called by each pipeline step. This approach simplifies the CI configuration and keeps the build logic centralized.

The pipeline performs the following steps:

  1. Version Extraction: Extracts the game version from the source code.
  2. Lint: Statically analyzes the Lua source files for errors.
  3. Minify: Builds and minifies the Lua source code.
  4. Docs: Generates API documentation from the source code.
  5. Export: Exports versioned TIC-80 artifacts (.tic and .html).
  6. Upload Artifacts: Uploads all generated artifacts to a remote server.
  7. Notify Update Server: Triggers a remote service to publish the new version.

Each step corresponds to a make ci-* target.

Step 1: Version Extraction

YAML
- name: version
  image: alpine
  commands:
    - 'apk add --no-cache make'
    - 'make ci-version'

What it does:

  • Uses a minimal Alpine Linux image.
  • Installs make.
  • Runs make ci-version, which reads the version from a Lua source file (inc/meta/meta.header.lua) and saves it to a .version file for subsequent steps to use.

Step 2: Lint

YAML
- name: lint
  image: alpine
  commands:
    - 'apk add --no-cache make lua5.4 lua5.4-dev luarocks gcc musl-dev'
    - 'ln -sf /usr/bin/lua5.4 /usr/bin/lua'
    - 'ln -sf /usr/bin/luarocks-5.4 /usr/bin/luarocks'
    - 'luarocks install luacheck'
    - 'make ci-lint'

What it does:

  • Installs Lua 5.4, luarocks, and luacheck.
  • Runs make ci-lint, which statically analyzes all Lua source files for syntax errors, unused variables, and other issues.
  • Fails the pipeline if any issues are found, preventing broken code from progressing.

Step 3: Minify

YAML
- name: minify
  image: alpine
  commands:
    - 'apk add --no-cache make lua5.4 curl'
    - 'ln -sf /usr/bin/lua5.4 /usr/bin/lua'
    - 'make ci-minify'

What it does:

  • Installs Lua 5.4 and curl.
  • Runs make ci-minify, which builds the project (concatenates source files) and then minifies the output.
  • Produces <project>.lua (minified) and <project>.original.lua (pre-minification backup for documentation generation).

Step 4: Docs

YAML
- name: docs
  image: alpine
  commands:
    - 'apk add --no-cache make lua5.4 lua5.4-dev luarocks gcc musl-dev zip'
    - 'ln -sf /usr/bin/lua5.4 /usr/bin/lua'
    - 'ln -sf /usr/bin/luarocks-5.4 /usr/bin/luarocks'
    - 'luarocks install ldoc'
    - 'make ci-docs'

What it does:

  • Installs Lua 5.4, luarocks, ldoc, and zip.
  • Runs make ci-docs, which generates API documentation from the pre-minification source (<project>.original.lua) using ldoc.
  • Zips the docs into a versioned archive (e.g., impostor-1.0.0-docs.zip) and creates an unversioned copy (impostor-docs.zip).

Step 5: Export

YAML
- name: export
  image: git.teletype.hu/internal/tic80pro:latest
  environment:
    XDG_RUNTIME_DIR: /tmp
  commands:
    - 'make ci-export'

What it does:

  • Uses a custom TIC-80 Pro Docker image.
  • Runs make ci-export, which reads the version from the .version file and exports the game. This generates:
    • A versioned .tic cartridge (e.g., impostor-1.0.0.tic).
    • A versioned .html.zip web build (e.g., impostor-1.0.0.html.zip).
  • Copies versioned artifacts to unversioned names (impostor.tic, impostor.html.zip) for consistency.

Step 6: Artifact Upload

YAML
- name: artifact
  image: alpine
  environment:
    DROPAREA_HOST: vps.teletype.hu
    DROPAREA_PORT: 2223
    DROPAREA_TARGET_PATH: /home/drop
    DROPAREA_USER: drop
    DROPAREA_SSH_PASSWORD:
      from_secret: droparea_ssh_password
  commands:
    - 'apk add --no-cache make openssh-client sshpass'
    - 'make ci-artifact'

What it does:

  • Installs make and SSH tooling.
  • Runs make ci-artifact, which uploads the generated .lua, .tic, .html.zip, and -docs.zip files to a remote server using scp.
  • Uses secrets for SSH authentication. The Makefile target reads the necessary environment variables.

Step 7: Update Notification

YAML
- name: update
  image: alpine
  environment:
    UPDATE_SERVER: https://games.vps.teletype.hu
    UPDATE_SECRET:
      from_secret: update_secret_key
  commands:
    - 'apk add --no-cache make curl'
    - 'make ci-update'

What it does:

  • Installs make and curl.
  • Runs make ci-update, which sends an HTTP curl request to an update server.
  • This notifies the server that a new build is available for publishing.
  • Uses a secret key to authorize the update.

Result

After a successful run:

  • The source code is linted for errors.
  • The game is built, minified, and exported with a version derived from its source code.
  • API documentation is generated and packaged.
  • All artifacts (.lua, .tic, .html.zip, -docs.zip) are uploaded to the server.
  • The public game index is updated automatically.

This pipeline enables fully automated TIC-80 releases where the entire build and release logic is managed by the project's Makefile.

Example file

https://git.teletype.hu/tools/tic80-tools/src/branch/master/example-woodpecker.yaml


Builder image

This document provides a guide for creating a Docker-based build environment specifically for compiling the TIC-80 Pro version to be used in automated pipelines.

Commercial Product Information

TIC-80 Pro is a commercial product that offers additional features and supports the ongoing development of the platform. The Pro version is available for purchase on itch.io.

While the TIC-80 source code is open, building the Pro version is intended for users who have purchased a license. If you have bought TIC-80 Pro, you are encouraged to use this Dockerfile to build your own Pro binary from source within a clean and isolated environment, ensuring consistency across your development and CI/CD workflows.

Dockerfile Explanation

The provided Dockerfile automates the setup of the compilation environment and the build process itself. Below is a step-by-step breakdown of how it works:

  1. FROM ubuntu:24.04 Sets the base image to Ubuntu 24.04 (Noble Numbat), providing a stable and modern Linux foundation for the build.

  2. RUN apt-get update && apt-get install -y ... Updates the package lists and installs all necessary development tools and libraries:

    • build-essential and cmake: Core tools for compiling C++ projects.
    • git: Required to clone the source code repository.
    • libsdl2-dev, libpipewire-0.3-dev, libwayland-dev, etc.: Libraries for graphics, audio, and system integration.
    • ruby-dev, lua5.4, libcurl4-openssl-dev: Dependencies for scripting languages and networking features supported by TIC-80.
    • The command ends with rm -rf /var/lib/apt/lists/* to keep the image size small by removing temporary cache files.
  3. RUN git clone --recursive https://github.com/nesbox/TIC-80 /opt/TIC-80 Downloads the TIC-80 source code from GitHub into the /opt/TIC-80 directory, including all necessary submodules.

  4. cd /opt/TIC-80/build && cmake ... Enters the build directory and configures the project using CMake with specific flags:

    • -DBUILD_PRO=On: This is the crucial flag that enables the Pro features during compilation.
    • -DBUILD_SDLGPU=On, -DBUILD_WITH_ALL=On: Enables all optional features and GPU support.
    • -DBUILD_STATIC=On: Ensures that the resulting binary is statically linked, making it more portable across different Linux environments.
  5. cmake --build . --parallel Starts the actual compilation process, utilizing multiple CPU cores to speed up the build.

  6. ENV PATH="/opt/TIC-80/build/bin:${PATH}" Adds the directory containing the newly built TIC-80 binary to the system's PATH, allowing you to run tic80 from anywhere inside the container.

  7. WORKDIR /workspace Sets the default working directory to /workspace, which is the intended location for mounting your project files.

  8. CMD ["/bin/bash"] Defines the default command to start a bash shell when the container is run, providing an interactive environment if needed.