The 2001 game, compiled natively from its decompiled Xbox source. It plays exactly as it shipped, and new Vulkan and Metal renderers make it look the way you remember.
Download · openh1.com · Discord · Bring your own game · Contributing
OpenH1 is a fork of OpenCE,
the community's port, and adds a Mac app with its own Metal renderer, a
Vulkan renderer, VR and more. It keeps OpenCE's netcode, so players of the
two can play together. OpenCE starts from the decompilation of
bnunu/halo-1, a fork of
punpckhdq/halo, of the Xbox build 2342
(cachebeta.exe, SHA-256
4cc87b45f721270392a96f1674ed2b5cd4a7bb4355faeab4531d1cf1884d9520).
- The original game, natively. Not emulation: the game's own code, with the same 30 ticks a second on every machine, so it plays as it shipped.
- New renderers. Vulkan on Linux, Windows, Android and the Steam Frame, Metal on the Mac, with SMAA, per-pixel dynamic lights and frames drawn between ticks at your display's rate (4K, 120 Hz and up).
- VR on the Steam Frame and OpenXR headsets: reload by hand, draw from holsters, raise the scope to your eye.
- 128 players online and on the LAN, up to 4 in split screen on each machine, and the campaign in co-op over the internet. Plays with OpenCE.
- Mods and Custom Edition maps, from the game's own menus.
| Original | OpenH1 | |
|---|---|---|
| Dynamic lights Rat Race, a frag grenade |
![]() |
![]() |
| Anti-aliasing Blood Gulch, enlarged 4× |
![]() |
![]() |
| Plasma glow Blood Gulch, a charged plasma pistol |
![]() |
![]() |
Real captures, the same moment twice. openh1.com has them side by side, with clips.
| Code | The Xbox game's decompiled C, compiled natively, with few and marked changes. Not emulation |
| Simulation | 30 ticks a second, as shipped, with the same calculations on every machine |
| Frames | One per refresh of your display, each drawn between the last two ticks; nothing the game calculates changes |
| Architecture | A 64-bit program, with the game compiled as a 32-bit-pointer guest inside it (arm64_32 on ARM, x32 on x86-64) |
| Renderers | One command stream into Vulkan 1.3 on Linux, Windows, Android and in VR, and into Metal on the Mac |
| Picture | SMAA or FXAA, anisotropic filtering, sharper shadows, per-pixel lighting, full model detail. One switch: Video Setup › Graphics › Preset, Classic or Enhanced |
| Display | Any resolution from 640 × 480, a field of view up to 150°, a HUD redrawn at 8× |
| Network | Plays online with OpenCE players; internet play needs no servers to set up |
| Mods | Texture, sound, text and model packs from the game's Mods menu; Custom Edition maps that share themselves |
| Releases | Every commit is built for every platform, and each build of master that passes is a release |
Contributions are welcome: refer to "Contributing" below. Players and contributors meet on the OpenH1 Discord.
GitHub Actions builds the game for each commit, and each build of master
that passes on all the platforms is a new release. These links download the
builds of the latest release:
| Platform | Release | Debug |
|---|---|---|
| macOS (Apple silicon, macOS 14.4 or later) | OpenH1.dmg | OpenH1-debug.dmg |
| Windows | OpenH1-Windows.zip | OpenH1-Windows-debug.zip |
| Linux x86-64 (also the Steam Deck) | OpenH1-Linux.zip | OpenH1-Linux-debug.zip |
| Linux arm64 | OpenH1-Linux-ARM64.zip | OpenH1-Linux-ARM64-debug.zip |
| Linux x86-64 VR | OpenH1-Linux-VR.zip | |
| Steam Frame VR (install) | OpenH1-Steam-Frame.zip | |
| Android (64-bit, Android 9 or later, Vulkan 1.3) | OpenH1-Android.apk | OpenH1-Android-debug.apk |
Use the release build to play. The debug build stops at the first failed assertion and writes it to the log. Use the debug build to find and report problems. The Releases page keeps the last five releases: if the latest build has a problem, get an older build there.
- macOS: open the
.dmgand drag OpenH1 to Applications. The app is signed with a Developer ID and notarized by Apple, so it opens like any other downloaded app. - Windows: unzip into a folder and start
halo.exe. Windows may say that it protected your PC: it says that of any app that is not signed, and this one is not. Choose More info, then Run anyway. Or install it with Scoop, with no warning:scoop bucket add openh1 https://github.com/OpenH1/scoop-bucket, thenscoop install openh1(refer to port/windows/README.md). - Linux and the Steam Deck: unzip, and open
install.shin the folder (on a Steam Deck, in Desktop Mode). It installs the game in~/Applications/OpenH1, asks for your game's disc image or maps folder, puts OpenH1 in the application menu and, on a Steam Deck, in Steam's library for Game Mode (the VR build's, as OpenH1 VR in~/Applications/OpenH1-VR). Or startbin/openh1where you unzipped it. The game needs a GPU and driver with Vulkan 1.3. The folders are laid out as a Unix prefix is (bin/,lib/,share/), for package managers too: refer to "Steam Deck" and "Packaging" in port/linux/README.md. - Android: download the APK on the phone and open it to install it
(Android asks you to allow installs from the browser the first time). An
install from before the project's own signing key must be uninstalled
once first: back up its
maps/andsave/folders. Refer to port/android/README.md.
The Windows, Linux and Android builds update themselves. At start-up they
look for a newer release, and ask if you want to install it (refer to
"Updates" in port/linux/README.md). On
macOS, download the new release. A Scoop install is updated by Scoop
(scoop update openh1), not by the game.
The port does not include the game data. You need your own, legally
obtained copy of Halo: Combat Evolved for the original Xbox: an Xbox disc
image (.xiso or .iso) made from a disc you own. OpenH1 does not supply
the game or say where to get it. How to make a disc image of your disc,
and how each build takes it: openh1.com/maps. All versions of the game operate. The maps of the European (PAL) version were made for a slower
console. The port changes them to play as the North American (NTSC) maps do,
so players of the two versions can play together.
- Start the game.
- At the first start, the game asks for the disc image. On Linux (the
Steam Deck and the Steam Frame too), the game finds it itself: put the
image in Downloads, on the Desktop, in your home folder, on an SD card or
USB drive, or next to the game, and choose it on the game's own screen,
with a controller, the keyboard or the mouse. This works in the Steam
Deck's Game Mode and needs no file picker. On Windows, select it in the
file picker (a disc image next to
halo.exeis used without one). The macOS app's open panel takes the disc image or the maps folder copied from the disc. - The game extracts the
maps/folder. Then the game starts.
The maps/ folder holds the Xbox maps only. If it holds Halo PC's maps
instead (a Halo PC or Custom Edition install's maps folder), the game says
so and stops: Custom Edition maps go in custom_maps/, beside maps/.
On Linux, the game puts maps/ in the folder of the release (next to
bin/). On Windows, the game puts maps/ next to the executable. On
macOS, a disc image's maps/ goes in
~/Library/Application Support/OpenH1, and a maps folder chosen instead
stays where it is. On
Android, copy the disc image to the phone first. The app puts maps/ in its
data folder. Refer to port/android/README.md.
Mods are folders of Halo PC tag files, as the Halo Editing Kit and Invader
write them, in mods/ next to maps/: texture, sound, text and model packs
that play over the maps' on your machine only, in any game. Each has a
mod.toml. Every mod in the folder is on; the main menu's Mods turns them
off and on and sets the order they load in.
Refer to docs/mods.md.
Each platform has its own instructions:
| Platform | Instructions |
|---|---|
| Linux x86-64 (x86-64 executable, Vulkan 1.3, SDL3) | port/linux/README.md |
| Linux arm64 (arm64 executable, Vulkan 1.3, SDL3) | port/linux/README.md |
| Linux VR (x86-64 and arm64, Vulkan 1.3; OpenXR headsets such as the Steam Frame) | port/linux/README.md |
| Windows (64-bit executable, Vulkan 1.3, SDL3; Windows 10 1903 or later) | port/windows/README.md |
| Android (arm64 app, Vulkan 1.3, SDL3) | port/android/README.md |
| macOS (Apple silicon: OpenH1.app, Metal) | port/macos/README.md |
| iOS and iPadOS (arm64, iOS 17.4 or later: OpenH1.app, Metal; built from source and sideloaded, not released yet) | port/ios/README.md |
The Linux README also gives the controls, the settings and the multiplayer functions. These are almost the same on all platforms.
The game can play system link games on a local network and on the internet:
- A system link game can have up to 128 players on up to 128 machines.
- Linux (x86-64 and arm64), Windows, macOS and Android machines can play in the same game.
- An invite link, or the server browser, lets a machine join a game on the internet (port/linux/README.md). No server of this project is necessary.
- The netcode is new. Each machine moves its own player at once, and the host makes the decisions for the game. Refer to port/linux/NETCODE.md.
To find people to play with, ask in #looking-for-game on the Discord.
You do not need the Xbox SDK. The port supplies the SDK declarations that the game uses. Refer to port/include/xdk.
To build the game:
- Install Python and ninja.
- Install the tools for your platform. Refer to the README for the platform.
- In the root folder of the repository, enter
python configure.py. - Enter
ninjawith the target for the platform:
| Target | Result |
|---|---|
ninja linux_x86_64 (on 64-bit x86 Linux) |
build/linux_x86_64/halo and libSDL3.so.0 (with python configure.py --vr, its VR mode) |
ninja linux_arm64 (on 64-bit ARM Linux) |
build/linux_arm64/halo and libSDL3.so.0 (with python configure.py --vr, its VR mode) |
ninja windows (on Windows, or on Linux after configure.py --windows-cross) |
build/windows/halo.exe and SDL3.dll; ninja windows_guest, its guest image alone, anywhere after configure.py --windows-guest |
ninja android_apk |
port/android/app/build/outputs/apk/debug/app-debug.apk |
ninja macos (on a Mac with Apple silicon) |
build/macos/OpenH1.app (and halo with libSDL3.0.dylib, for development); ninja macos_dmg: OpenH1.dmg |
ninja ios (on a Mac with Apple silicon and Xcode's iOS SDK) |
build/ios/OpenH1.app, signed for development with configure.py --ios-team; ninja ios_install installs it on the connected device; ninja ios_sim: the Simulator's |
If you enter ninja without a target, ninja builds the game for the
computer that you use: on 64-bit x86 Linux, ninja linux_x86_64.
The Linux builds are 64-bit, and draw with Vulkan 1.3: configure.py
downloads the Vulkan headers with musl and SDL3, so the build needs no
Vulkan development packages. Refer to
port/linux/README.md.
tools/ci_build.py makes the same builds as GitHub Actions. For example,
enter python tools/ci_build.py linux_x86_64 release.
Give these options to configure.py:
| Option | Result |
|---|---|
| (none) | A debug build. A failed assertion stops the game. |
--release |
A release build. The game does not examine assertions, as in the retail game. |
--vr |
The VR mode (OpenXR) in the Linux build of the computer. Refer to "VR" in port/linux/README.md. |
--pgo=off |
No profile-guided optimization. |
--profile |
A profiling build. It records CPU times. Refer to "Profiling builds". |
--guest-llvm=system, --guest-llvm=FOLDER |
The guest builds (Linux arm64 and x86-64, Android, macOS, Windows) compile the guest with clang and the LLVM tools on the PATH, or with the LLVM in FOLDER, not with the pinned LLVM. Refer to "The guests' compiler". |
--guest-llvm-cache FOLDER |
The folder for the pinned LLVM (else ~/.cache/openh1, on macOS ~/Library/Caches/openh1). |
--guest-base |
The Linux arm64 and Android builds put the guest's memory at a base that the host chooses, not in the low 4 GB (a base register: tools/guest_base_register.py). The 64-bit x86 build has none: with it, ninja linux_x86_64 stops with the reason. |
--ios-team TEAM |
ninja ios signs the iOS app for development with the team's certificate and a provisioning profile that Xcode makes (tools/ios_provision.py; Xcode signed in to the team's account). Without it the app is signed ad hoc. --ios-identity and --ios-bundle-id choose another certificate and bundle identifier. Refer to port/ios/README.md. |
The Linux arm64 and x86-64, Android, macOS and Windows builds compile the
game as a guest image (arm64_32 or x32 code). On all computers, the
guest is compiled and linked by the same LLVM: release 22.1.8 from
LLVM's releases, for
64-bit x86 Linux, 64-bit ARM Linux, macOS on Apple silicon and 64-bit
Windows. The first
configure.py downloads it (approximately 1.5 GB, checked against its
SHA-256) and keeps clang, ld.lld and the LLVM tools that the builds use
(approximately 700 MB) in ~/.cache/openh1 (on macOS
~/Library/Caches/openh1, or the folder of --guest-llvm-cache). The
version and the checksums are in tools/guest_toolchain.py. The hosts
use the compiler of the system. On Linux, the LLVM tools need glibc 2.34
or later, libstdc++ and zlib; LLVM's ld.lld is also linked to
libxml2.so.2, for Windows links only, which some distributions (Arch,
CachyOS) no longer have, so a small stand-in for it is written beside the
tools (tools/library_stand_in.py).
A compiler that you give for a build (--linux-arm64-cc,
--linux-x86-64-cc, --android-guest-cc, --macos-cc,
--macos-guest-cc) is used instead, with the LLVM tools on the PATH, as
with --guest-llvm=system.
The builds use profiles of the game to optimize the code:
pgo/halo_linux.profdata, for every build (they are all guest builds: Linux, Android, macOS, Windows).
The profiles need clang 22 or later. With an older clang, the builds do not use the profiles. The guest builds' pinned LLVM (refer to "The guests' compiler") reads them on all platforms.
The profile was recorded by the 32-bit Linux build, which is gone: the guest builds cannot record one yet, and use it as it is (code changed since then goes without).
A profiling build records where the game spends its time.
- Enter
python configure.py --profile, then build as usual. - Start a recording. Enter
profile_recordin the console (or the telnet console), or setdebug.profile_record = trueinconfig.toml. To record each game of a session, also setdebug.profile_record_when = "game". - Stop the recording. Enter
profile_stop, load another map, or quit.
The game writes numbered .part<n>.json files under profiles/ in its data root
and logs their paths. Parts are retained after the recording stops. Logs go to
standard error; a Windows release build without standard error writes them to
halo.log next to halo.exe.
tools/net_report.py is a helper for developers. Enter
python tools/net_report.py <recording.part1.json> to read a recording
as tables. The command also writes <recording>.summary.txt, a short text
file.
| Command | Result |
|---|---|
profile_record [seconds] |
Starts a recording. With a number of seconds, the recording stops after that time. |
profile_stop |
Stops the recording. |
debug.profile_memory sets the memory of a recording in MB (default 256,
from 4 to 1024). A recording has no length limit:
the game writes a part each time the memory is full. Refer to "Settings" in
port/linux/README.md.
On Android, the files are in /sdcard/Android/data/com.openh1.openh1/files/profiles/.
Enter adb pull to copy the recording parts to a computer.
A profiling build plays with normal builds.
The tests are listed in AGENTS.md ("Testing"). Most run without the game data, in GitHub Actions too.
One check needs the retail maps, so it runs on your own computer (or on a
self-hosted runner), not in GitHub Actions: tools/net_compare.py plays
two builds together in a network game on one computer and checks that they
stay in step. Run it when a change can alter how a build calculates the
game, as a new platform, compiler or architecture does, before it is
merged. For example, to check your build against the latest release:
python tools/net_compare.py --a build/linux_x86_64/halo --b <release folder>/bin/openh1 \
--data <folder with maps/> --maps bloodgulch,beavercreek,hangemhigh --swapEach game prints PASS or FAIL. A FAIL names the first player, tick and value that differ. Refer to "Comparing two builds" in port/linux/NETCODE.md.
Pull requests are welcome, from small fixes to whole renderer features. We review them promptly, and merge what is ready.
- Fork the repository and branch from
master. - Read AGENTS.md: the layout, the build, the conventions (the
game's sources are C89,
gnu89), the tests, and what must stay deterministic. - Open a pull request. GitHub Actions builds it for Android, Windows,
macOS and the Linux builds, and runs the tests (debug builds off
master, so a check takes minutes). - Say what you tested and how, and what still needs a device to check.
Fixes from OpenCE are welcome too. If you have a pull request waiting in OpenCE, open it here as well, or tell us about it. We bring good ones in with their authorship kept and credit given, as for OpenCE's #328, #369 and #392.
Keep network play compatible. A change to what the game sends, or to how
it calculates the game, needs HALO_PORT_NETWORK_VERSION and a
tools/net_compare.py run (refer to "Testing"), so that OpenH1 and OpenCE
players can still play together.
Report problems on the issue tracker,
with the build number (the main menu shows it) and debug.txt. For help,
or to talk about a change before you make it, ask on the
Discord: #help, and #dev-general.
OpenH1 is free software: you can give it to others and change it under the
terms of the GNU Affero General Public License as published by the Free
Software Foundation, version 3 of the License or (at your option) any later
version (AGPL-3.0-or-later). It comes with no warranty. The full text is in
LICENSE.
- From the change. The AGPL applies from the commit that made the change, and to each release built from that commit or a later one. Earlier releases, and the source at every earlier commit, were released under CC0 1.0 and stay that way. (OpenH1 took the change with its merge of OpenCE, which had made it.)
- What OpenH1 builds on. The decompilation of punpckhdq/halo is under the AGPL 3.0 from 17 October 2026, and under CC0 1.0 before that date. bnunu/halo-1 is under CC0 1.0.
- Contributions are under
AGPL-3.0-or-later. A change taken from a project under GPL 3.0 keeps that licence and its notices; the GPL 3.0 and the AGPL 3.0 let the two be combined (section 13 of each). - Hosts and servers. If you change the game and let other persons play
with your version over a network (for example, as the host of an internet
game, or on a web site), the AGPL asks you to offer them the source of
your version (section 13). The game as released has its source here, and
each release's source is its tag (
build-<n>). - Third-party code, fonts and art keep their own licences, which are
next to them (
port/third_party,port/assets/fonts,port/assets/icons,port/assets/text_filter). The release downloads and the web site'slicenses.txtcarry their notices. - Halo is not covered. The licence covers the work of OpenH1's and OpenCE's authors. It gives no rights in Halo, its maps or anything else that Microsoft owns.
OpenH1 is an unofficial fan project, not endorsed by or affiliated with Microsoft, Xbox Game Studios, Halo Studios or Bungie. Halo is a trademark of Microsoft Corporation. No game data is included: you need your own copy of the game.






