# O3DE Flatpak Repackage the official [Open 3D Engine](https://o3de.org/) Linux release as a **Flatpak** so it can be installed on any distribution — not only Debian/Ubuntu. A Gitea Actions workflow checks daily for a new O3DE release, builds the Flatpak, and publishes it as a static [OSTree](https://ostreedev.github.io/ostree/) Flatpak repository on the `pages` branch of this repo. You add that as a Flatpak remote and `install` / `update` like any other app. > **Status:** community / unofficial. O3DE is a large application (~15–18 GB > installed); building and hosting it is heavy. Treat this as best-effort. --- ## Installing (end users) ```sh # Flathub provides the runtime O3DE needs flatpak remote-add --if-not-exists flathub https://flathub.org/repo/flathub.flatpakrepo # Add this repo flatpak remote-add --if-not-exists o3de \ https://git.pc-heini.de/pc-heini/o3de-flatpak/raw/branch/pages/o3de.flatpakrepo flatpak install o3de org.o3de.O3DE flatpak run org.o3de.O3DE ``` Later updates: ```sh flatpak update org.o3de.O3DE ``` > The repo is currently **unsigned** (no GPG). Flatpak will add it with GPG > verification disabled. See *Signing* below to harden this. --- ## How it works | File | Purpose | | --- | --- | | `scripts/make-flatpak.sh` | **The build.** Unpacks the official `o3de_*.deb` into `/app`, bakes in Python, and exports an OSTree repo using `flatpak build-init`/`build-finish`/`build-export` — no `flatpak-builder`, no bubblewrap, no privileged container. | | `o3de-wrapper.sh` | Entry point. Finds the versioned `o3de` Project Manager binary inside the sandbox and sets `LD_LIBRARY_PATH`. | | `org.o3de.O3DE.desktop` | Desktop entry under the Flatpak app-id. | | `org.o3de.O3DE.metainfo.xml` | AppStream metadata (version stamped at build time). | | `scripts/get-latest-version.sh` | Resolves the latest `.deb` URL, version, and SHA-256 from o3debinaries.org. | | `scripts/build.sh` | Download + build + test the Flatpak locally (wraps `make-flatpak.sh`). | | `org.o3de.O3DE.yaml` | Equivalent `flatpak-builder` manifest — kept as an **alternative** for builders that have a privileged/bwrap-capable environment. Not used by CI. | | `.gitea/workflows/build-flatpak.yml` | CI: detect new version → build → publish to `pages` → tag `vX.Y.Z`. | The engine ships as a Debian package at a predictable URL (`https://o3debinaries.org/main/Latest/Linux/o3de_.deb`). The build extracts it (`ar` + `tar`) and copies the payload into the Flatpak's `/app`. The version directory inside the `.deb` changes every release, so the wrapper discovers the executable at runtime rather than hard-coding a path. > **Want the full story?** O3DE is an engine + SDK that compiles code and writes > into its own install tree at runtime, while a Flatpak gives it a **read-only > `/app`**. Reconciling those two facts is most of the work here. > **[`docs/DESIGN.md`](docs/DESIGN.md)** documents every non-obvious decision, the > read-only-`/app` problems and their fixes, and how to debug/maintain this across > O3DE releases. Read it before changing the build. --- ## CI requirements (Gitea Actions) The workflow targets a **self-hosted `act_runner`**. Because O3DE is large: - **Disk:** budget **60 GB+** free. The build needs roughly 2–3× the installed size (extracted payload in `build-dir` + a copy committed into the OSTree `repo/`). The job deletes `build-dir` before publishing to cut peak usage, but it can still be tight. If builds fail on space, that's the first thing to check. - **No privileged container required.** The build avoids `flatpak-builder`/bwrap and uses `flatpak build-init`/`build-finish`/`build-export`, which only touch files and the OSTree repo. A plain unprivileged job container works. - **Runner label:** the job uses `runs-on: ubuntu-latest`. Change it if your runner is registered with a different label. - **Token:** publishing force-pushes the `pages` branch and creates a `vX.Y.Z` tag. The auto-provided `GITHUB_TOKEN` (with `contents: write`) usually suffices. If your instance restricts it, create a Personal Access Token with repo write access and add it as a secret named **`PUBLISH_TOKEN`** — the workflow prefers it automatically. It runs on three triggers: - **`push` to `main`** — rebuilds whenever the build itself changes (always builds, even for an already-published version, so you can test your change). Docs-only changes (`README.md`, `docs/**`, `LICENSE*`, `.gitignore`) are ignored. Scoped to `main` so the `pages`/tag pushes the job makes don't re-trigger it. - **daily `cron`** — picks up a **new O3DE binary release**; only builds when the upstream version has no matching `vX.Y.Z` tag yet, so most days are cheap no-ops. - **`workflow_dispatch`** — manual run from the Gitea Actions UI, with an optional **force** rebuild. --- ## Building locally ```sh # flatpak + curl + python3/setuptools (to pre-build the o3de sdist) sudo apt install flatpak python3-setuptools # or your distro's equivalent ./scripts/build.sh ``` Then install from the local `repo/` and run: ```sh flatpak remote-add --user --no-gpg-verify o3de-local repo flatpak install --user o3de-local org.o3de.O3DE flatpak run org.o3de.O3DE ``` --- ## Signing (recommended hardening) The first iteration publishes an unsigned repo for simplicity. To sign: 1. Generate a key: `gpg --quick-gen-key "O3DE Flatpak" default default never` 2. Export the public key and add `GPGKey=` to the generated `.flatpakrepo`. 3. Pass `--gpg-sign=` to both `flatpak-builder` and `build-update-repo`, and provide the private key to CI via a secret. Until then, users add the remote with GPG verification disabled. --- ## Caveats These were confirmed by inspecting and running the v26.05 package (`opt/O3DE/26.05/…`): - **Layout**: the package installs everything under `/opt/O3DE//`, with the launcher at `bin/Linux/profile/Default/o3de` and ~270 `.so` files beside it (hence the wrapper's `LD_LIBRARY_PATH`). If a future release moves things, adjust `o3de-wrapper.sh` and the manifest. - **Runs against `org.freedesktop.Sdk`, not `Platform`.** O3DE's package dependencies are a *build toolchain* (clang/ninja/cmake/pkg-config) because the engine compiles project code at runtime. Those live in the SDK. Users therefore pull the SDK runtime (larger than Platform) on install — Flatpak does this automatically from Flathub. - **Python is per-user, not baked in.** O3DE needs a Python venv under `~/.o3de` (writable), keyed to the engine path, so it can only be created at runtime — the build can't bundle it. The Project Manager GUI does **not** create it itself, so the wrapper (`o3de-wrapper.sh`) runs `python/get_python.sh` on launch when the venv is missing or stale. The **first launch downloads Python and can take several minutes with no window on screen** — that's expected; subsequent launches are instant. (cmake, which `get_python.sh` needs, comes from the Sdk runtime.) - **The o3de CLI install (read-only `/app`).** On first launch O3DE installs its own `o3de` CLI from `scripts/o3de` into the per-user `~/.o3de` venv. By default `python/get_python.sh` does an *editable* install (`pip install -e`), which writes an `egg-info` next to the source under read-only `/app` and fails. `get_python.sh` has a built-in immutable-install hook (the Snap path): if a prebuilt sdist exists at `scripts/o3de/dist/o3de-1.0.0.tar.gz` it installs that (non-editable) instead. The build pre-creates that tarball (`python3 setup.py sdist`) while the tree is still writable, so at runtime the CLI lands in the writable venv and nothing is written to `/app`. (The build also patches every `cmake/LYPython.cmake` to a non-editable install, covering the separate project-build CMake-configure path.) If a future release renames the package or bumps its version away from `1.0.0`, the build fails fast — those are the lines to re-check. - **Engine-path resolution needs `SNAP`/`SNAP_BUILD`.** Because the `o3de` CLI is installed non-editably, its package lives in the per-user venv, so O3DE's `manifest.get_this_engine_path()` (which walks up from the package `__file__`) would resolve into the venv and fail to find `engine.json`. O3DE has a built-in override for immutable installs: when `SNAP` and `SNAP_BUILD` are set it returns `$SNAP/$SNAP_BUILD`. The wrapper sets them to the engine root. (Confirmed these vars are read *only* there — no other snap-specific behaviour is triggered.) - **The Project Manager's own user folder is read-only (cosmetic).** With no project open, O3DE puts its engine-level *user* folder (asset cache, metrics, `UserSettings.xml`) under `/.../user`, i.e. read-only `/app`. You'll see `Couldn't find a valid asset cache folder…`, `cannot write to temp file … UserSettings.xml`, and a metrics warning at startup. These are **non-fatal** — the Project Manager runs fine; it just doesn't persist its *own* window/UI settings between runs. The documented override (`/O3DE/Runtime/FilePaths/SourceProjectUserPath`) does **not** help: O3DE recomputes that path from the engine root during bootstrap and overwrites a `--regset`. Real project data (projects you create, their caches) lives under your home directory and is fully writable, so actual work is unaffected. - **Launcher icon.** Shipped as `org.o3de.O3DE.png` (the `.deb` itself has only in-editor asset icons). It's kept *inside* the app so the running window/taskbar shows it, but removed from the *exported* set because `flatpak build-export` validates exported icons in a bwrap sandbox that fails in an unprivileged container. Consequence: the host menu launcher icon is generic. A privileged runner would let us export it properly. - **GPU / drivers:** the renderer needs working GPU access. The manifest grants `--device=dri`/`--device=all`; on some setups you may also want the matching GPU driver extension from Flathub. - **Sandbox filesystem:** `--filesystem=home` lets the Project Manager create and open projects under your home directory. Tighten or widen to taste. - **Hosting via raw branch URLs** works because Flatpak fetches individual files (`summary`, `config`, `objects/…`). Gitea serves these from the `pages` branch. If you later put a real static web host in front of it, just change `Url=` in the `.flatpakrepo`. --- *Not affiliated with or endorsed by the Open 3D Foundation. O3DE is licensed under Apache-2.0 / MIT.*