inkwell is now a published module (engines/inkwell v0.1.0) rather than a sibling checkout, so a project that depends on it needs GOPRIVATE — our forge is not proxy.golang.org and not in the public checksum database. Set in both the builder image and the Makefile template, so it holds whether or not the image has been rebuilt. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
ebitengine-tools
CI/CD templates for Ebitengine (Go) game projects, in the same spirit as tic80-tools.
example-makefile.make— project Makefile: local dev targets (build,wasm,export,watch,clean), native binary targets (binaries,binary-win-x86,binary-win-x64,binary-linux-x64) and the mac-host release targets (binaries-mac,mac-release).example-woodpecker.yaml— a one-line marker (platform: ebitengine): the full pipeline (version → build → binaries → artifact → publish) is served by the update server's Woodpecker configuration extension — preview it withcurl "https://teletypegames.org/build/config?platform=ebitengine".example-tasks.json— VS Code.vscode/tasks.jsonwith the common dev tasks: Run (go run ., default build task,Cmd+Shift+B), Build & Run, Build WASM and Make build.web/index.html— the HTML shell downloaded bymake exportand packaged next to the.wasmbuild.
Usage in a game repo
- Copy
example-makefile.maketoMakefileand setPROJECT(the native binary is built tobin/$(PROJECT)). - Copy
example-woodpecker.yamlto.woodpecker.yaml(a one-line marker — the pipeline itself is served by the update server; addname:when the software name differs from the repo name) and add theapplication_tokensecret in Woodpecker (an ApplicationToken with theupdate+uploadscopes, created in the admin). - Copy
example-tasks.jsonto.vscode/tasks.jsonand replace the binary name (ebitenginedemo) with$(PROJECT).
The served pipeline uploads $(PROJECT)-$(VERSION).html.zip plus the native
binary zips ($(PROJECT)-$(VERSION)-<target>.zip, currently win-x86,
win-x64, linux-x64) via /build/upload, then triggers
/build/publish?platform=ebitengine&name=$(PROJECT)&version=$(VERSION).
The updater picks up the binary zips by naming convention and attaches
them to the release as assets (see teletypegames/NOTES_BINARY_PLAN.md).
Binary zip layout: a single root folder
($(PROJECT)-$(VERSION)-<target>/) containing the executable (plus
LICENSE/README.md when present). The zips are created with unix zip,
so the executable bit survives on the linux binary.
mac targets (mac-x64, mac-arm64)
Ebitengine requires cgo on darwin (GLFW/Metal — purego does not cover
it), so the mac targets cannot be cross-compiled from the linux builder.
They are built on a mac host instead, packaged as a minimal
.app bundle (generated Info.plist, ad-hoc codesign):
make mac-release VERSION=x.y.z UPDATE_SECRET=...
This builds both mac zips, uploads them via /build/upload and re-triggers
/build/publish — the updater attaches the new assets to the already existing
release, so run it after the CI pipeline has created the release.
Ad-hoc signature means Gatekeeper shows the "unidentified developer"
warning (right-click → Open); proper signing/notarization needs an
Apple Developer account.
Builder image
builder.Dockerfile bakes the pipeline's build-step dependencies
(Go + git/make/zip/curl/jq and the X11/GL/ALSA dev libraries needed by
the cgo linux-x64 build) into
git.teletypegames.org/internal/ebitengine-builder. Debian-based so
the linux binary links against glibc:
docker build --platform linux/amd64 -f builder.Dockerfile \
-t git.teletypegames.org/internal/ebitengine-builder:latest .
docker push git.teletypegames.org/internal/ebitengine-builder:latest
Detailed documentation lives on the wiki: /development/ebitengine.