---
title: Godot
url: 'https://wiki.teletypegames.org/platforms/godot'
markdown: 'https://wiki.teletypegames.org/platforms/godot.md'
lang: en
date: '2026-08-03'
description: 'Godot is an open source 2D and 3D game engine with a visual editor. Scripting in GDScript or C#. Website: https://godotengine.org Tutorials 12 Popular Games Made With The Godot Engine Basics | Godot Engine Fundamentals - I. Pong Enjoyable Game Architecture | Chickensoft — Open Source Tools for…'
taxonomy:
  tag:
    - howto
---

# Godot

Godot is an open source 2D and 3D game engine with a visual editor. Scripting in GDScript or C#.

**Website:** https://godotengine.org

# Tutorials

- [*12 Popular Games Made With The Godot Engine*](https://www.thegamer.com/godot-engine-popular-games-best/#getting-over-it-with-bennett-foddy)
- [*Basics | Godot Engine Fundamentals - I. Pong*](https://jatekfejlesztes.online/tutorials/godot-kezdoknek-i-pong/tpages/alapozo)
- [*Enjoyable Game Architecture | Chickensoft — Open Source Tools for Godot and C#*](https://chickensoft.games/blog/game-architecture/)
- [*I Used Godot For 100 Hours, Here’s What I Learned*](https://www.youtube.com/watch?v=YVjT0OeE4P0)
- [*Godot Game Development – Crash Course for Beginners*](https://www.youtube.com/watch?v=S8lMTwSRoRg)
- [*Game Development Basics in Godot Engine*](https://www.youtube.com/watch?app=desktop&v=1LXukLw93uQ)
- [*How To Structure Your Godot Project (so You Don't Get Confused)*](https://new.pythonforengineers.com/blog/how-to-structure-your-godot-project-so-you-dont-get-confused/)

---

# Makefile

The Godot editor runs headless and exports the web build (HTML5/WASM) plus the desktop binaries. Templates are in [godot-tools](https://git.teletypegames.org/build/godot-tools):

- `example-makefile.make` → `Makefile`, then set `PROJECT`
- `example-export_presets.cfg` → `export_presets.cfg` (presets: `Web`, `Windows x86`, `Windows x64`, `Linux x64`, `Mac universal`)
- in `Mac universal` set `application/bundle_identifier`

Two settings that are easy to miss:

```ini
# project.godot — the arm64 macOS slice fails to export without this
[rendering]
textures/vram_compression/import_etc2_astc=true
```

```ini
# export_presets.cfg, Web preset — no threads, so the game runs without COOP/COEP headers
variant/thread_support=false
```

## Variables

| Variable | Description | Default |
|---|---|---|
| `PROJECT` | Name used in output filenames | `godotdemo` |
| `GODOT` | Godot editor binary | `godot` |
| `EXPORT_PRESET` | Preset in `export_presets.cfg` | `Web` |
| `DIST_DIR` | Artifact directory | `dist` |
| `WEB_DIR` | Raw web export | `dist/web` |
| `VERSION_FILE` | Version file for CI | `.version` |

## Targets

```sh
make build                     # godot --headless --import, creates .godot/ cache
make run                       # godot --path .
make web                       # export the Web preset into dist/web/
make export VERSION=1.0.0       # web export packed as godotdemo-1.0.0.html.zip
make binaries VERSION=1.0.0     # all desktop targets
make binary-win-x64 VERSION=1.0.0  # one target only
make watch                     # re-import on .gd / .tscn change (needs fswatch)
make clean                     # remove dist/ and .godot/
```

`build` is also a quick "does the project load" check. Run it on a fresh checkout before any export.

Desktop notes:

- Godot cross-exports every desktop platform from any host, including the linux CI image.
- macOS is one universal (intel + arm) build. Per-arch export would need custom templates.
- The `.app` is ad-hoc signed by Godot (`codesign/codesign=1`); arm64 macOS refuses unsigned binaries.
- Windows and Linux embed the `.pck` in the executable, so each zip holds a single file.
- Every zip follows the ReleaseAsset convention: one root folder, plus LICENSE and README.md when present.

## VS Code

Copy `example-tasks.json` to `.vscode/tasks.json`. Tasks: **Run** (default, `Cmd+Shift+B`), **Edit**, **Export Web**, **Make build**.

## Generated artifacts

| File | Description |
|---|---|
| `dist/web/` | Raw web export (index.html, .js, .wasm, .pck) |
| `godotdemo-<version>.html.zip` | Web build |
| `godotdemo-<version>-win-x86.zip` | Windows 32-bit |
| `godotdemo-<version>-win-x64.zip` | Windows 64-bit |
| `godotdemo-<version>-linux-x64.zip` | Linux 64-bit |
| `godotdemo-<version>-mac-universal.zip` | macOS universal `.app`, ad-hoc signed |

## Requirements

Local only: `make`, a Godot 4.x binary with **export templates** (web + desktop), `export_presets.cfg`, `zip`, `unzip`, and `fswatch` for watch mode. CI needs nothing in the repo.

---

# Pipeline

Game repos contain **no pipeline YAML and no CI make targets**. Woodpecker asks the update server, and WarpEngine serves the whole config from `/build/config` (template `lib/warp_engine/ci/woodpecker/platforms/godot/pipeline.yaml.erb`).

The repo needs three things:

```yaml
# .woodpecker.yaml
platform: godot
```

- `metadata.json`
- the `application_token` Woodpecker secret: a WarpEngine ApplicationToken with `update` + `upload` scopes
- `name: <software>` in the marker only when the software name differs from the repo name

Builder images (e.g. `godot-builder:4.7.1`) come from the update server's `ci_platforms` config. Preview the served pipeline:

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

## Steps

| Step | What it does |
|---|---|
| 1. version | the engine's shared step (since WarpEngine 1.7): the version from `metadata.json`; 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. build | in the `godot-builder` image: import, export the `Web` preset, then the four desktop targets; pack each into its own zip |
| 3. upload | **on the tag only:** copy `metadata.json` to `godotdemo-<version>.metadata.json`, then `POST /build/upload` per file with the `X-Update-Secret` header |
| 4. publish | **on the tag only:** `POST /build/publish` with `name`, `platform`, `version` |
| 5. 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 is [godot-ci](https://github.com/abarichello/godot-ci) (headless editor **and the matching export templates**) with `make`, `zip`, `unzip` and `jq` added, so no step runs `apt-get`. It is built from `builder.Dockerfile` in godot-tools.

```sh
curl -X POST -H "X-Update-Secret: <SECRET>" \
  "https://teletypegames.org/build/publish?name=godotdemo&platform=godot&version=1.0.0"
```

## Result

Web build and four desktop targets, each in its own zip, attached to the release as ReleaseAssets and downloadable from the catalog page. The public game index updates itself.

'; 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: [Ebitengine](https://wiki.teletypegames.org/platforms/ebitengine.md)
- Next: [Löve](https://wiki.teletypegames.org/platforms/love.md)
