Skip to content

About

An OpenTrack compatible head tracking mod for Half Life 2

Resources

Stars

1 star

Watchers

0 watching

Forks

Repository files navigation

Half-Life 2 Head Tracking

Half-Life 2 running with this mod

An unofficial head tracking mod for Half-Life 2 that moves the view with your head while your mouse or controller keeps aiming, driven by a webcam, phone, or any OpenTrack compatible tracker, with no VR headset required.

Features

  • Decoupled look and aim - your head moves the camera the frame is rendered from, while the mouse or controller still controls where you shoot. The player's own eye angles and position are never written, so weapon fire, traces, physics and NPC behavior are unchanged.
  • 6DOF tracking - yaw, pitch and roll, plus positional lean, peek and duck.
  • Works with any OpenTrack compatible tracker - free options available for PC, iOS and Android

Requirements

  • Half-Life 2 on Steam (app 220). The supported routes are the default hl2_complete campaign and steam_legacy's hl2 campaign, validated with the client DLLs dated 27 June 2025.
  • A tracking source that sends the OpenTrack UDP protocol, such as OpenTrack with a webcam.
  • 64-bit Windows 10 or 11. The game itself is a 32-bit process, so the mod and its loader are both x86.

The mod discovers and validates the required functions, layouts and interfaces at startup, including on an unlisted build. If those checks fail, it leaves the camera unchanged and logs the reason. This does not guarantee compatibility with every future game update.

Installation

Lopari

Download Lopari, choose Half-Life 2, and click Play with head tracking.

Standalone Installer

  1. Download the installer ZIP (HalfLife2HeadTracking-v<version>-installer.zip) from the Releases page.
  2. Extract it anywhere.
  3. Double-click install.cmd. It finds Half-Life 2, places the loader and the mod in <game>\bin\, and reports what it did.
  4. Configure OpenTrack (or your tracker app) to send UDP to 127.0.0.1:4242.
  5. Launch the game.

If the installer cannot find your copy of the game, point it at the folder yourself. Either pass the path as an argument:

install.cmd "D:\Games\steamapps\common\Half-Life 2"

or set the override environment variable before running it:

$env:HALF_LIFE_2_PATH = "D:\Games\steamapps\common\Half-Life 2"
.\install.cmd

Both expect the folder that contains hl2.exe.

Manual Installation

For placing the files by hand, or when using the Nexus ZIP (HalfLife2HeadTracking-v<version>-nexus.zip), which contains the deploy subtree only and no loader.

  1. Download Ultimate ASI Loader and take dinput8.dll out of Ultimate-ASI-Loader.zip. That asset is the x86 build; the x64 one cannot load into Half-Life 2.
  2. Rename it to winmm.dll and put it in <game>\Half-Life 2\bin\. Source loads its DLLs out of bin\, so a copy next to hl2.exe is never loaded and nothing happens. If another mod already put an Ultimate ASI Loader proxy in that folder, leave it alone and skip this step.
  3. Put HalfLife2HeadTracking.asi in that same bin\ folder. The Nexus ZIP mirrors the game folder, so extracting it over <game>\Half-Life 2\ lands it there for you.
  4. Launch the game once. The mod writes CameraUnlock.ini and HeadTracking.log next to hl2.exe.

Setting Up OpenTrack

In OpenTrack, set Output to UDP over network and enter host 127.0.0.1, port 4242. Map yaw, pitch and roll, and X, Y and Z as well if you want positional tracking. Press Start, then launch the game.

Centering is done in your tracker. Use OpenTrack's Center bind, SteamVR's reset, or the CENTER button in your phone app.

VR Headset Setup

  1. Connect the headset to the PC over Air Link, Virtual Desktop or a link cable.
  2. Start SteamVR and let it finish setting the headset up.
  3. In OpenTrack, set Input to the SteamVR tracker.
  4. Leave Output on UDP over network, host 127.0.0.1, port 4242.

Webcam Setup

Set OpenTrack's Input to neuralnet tracker. It tracks your face from a plain webcam, with no markers, clip or IR hardware. Even lighting on your face is what it needs most.

Phone App Setup

The mod accepts one thing: OpenTrack UDP packets on port 4242. A phone app is usable here if it sends that protocol itself, or ships a PC-side companion that does. Check your app against that first.

For an app that does send it, what decides the wiring is how much filtering it does before the packet leaves the phone. An app that filters on-device can point straight at this PC's LAN address (run ipconfig to find it) on UDP port 4242. A raw or lightly filtered feed sent direct will jitter, because the mod's smoothing is sized to take the edge off a clean signal rather than to rescue a noisy one. That app should send into OpenTrack instead, on a spare port such as 5252, with OpenTrack's output going to 127.0.0.1:4242 so its filters and curves clean the feed up first.

The test is quicker than the reading: send direct, hold your head still, and if the view drifts or shakes, route it through OpenTrack.

I made Headcam so decent tracking was free for anybody with a phone already in their pocket. It filters on-device, so it can send direct. Any other app that filters enough works exactly the same way.

A phone on WiFi is a remote connection and gets RemoteSmoothing. So does a tracker running on this same PC that sends to the machine's LAN address instead of 127.0.0.1, because the classifier sees a transport and not a machine. Only loopback counts as local.

Controls

Each action has a list of keys, and any key in it fires the action. By default each list holds a nav-cluster key and a chord, so use whichever your keyboard has:

Action Default keys Setting
Toggle tracking End, Ctrl+Shift+Y ToggleKey
Cycle tracking mode PageUp, Ctrl+Shift+G CycleTrackingModeKey
Toggle yaw mode PageDown, Ctrl+Shift+H YawModeKey

Page Up / Ctrl+Shift+G cycles tracking mode:

  1. 6DOF, rotation and position together
  2. Rotation only, positional tracking off
  3. Position only, rotational tracking off
  4. Back to 6DOF

Page Down / Ctrl+Shift+H switches yaw between horizon-locked (yaw around the world up axis, the default) and camera-local (yaw composed with the camera's current pitch and roll).

The tracking mode and the yaw mode are saved to CameraUnlock.ini the moment they change, so the next launch starts in the mode you left it in. End turns tracking on and off for the session only and saves nothing: whether tracking is on at launch is EnableOnStartup.

Every key in the three lists, the chords included, can be changed or removed under [Hotkeys] in CameraUnlock.ini, for example ToggleKey=F8, Ctrl+Shift+Y. Hotkeys only fire while the Half-Life 2 window has focus.

Configuration

The mod reads its settings from CameraUnlock.ini in the game folder, and creates the file when it starts and finds none. Edit it with any text editor.

A setting set to default takes its value from Defaults.ini, which every head tracking mod that keeps its settings in CameraUnlock.ini reads. Head tracking mods that keep their settings in another file do not read it. Writing a value in place of default changes that setting for this game only. When the mod saves a setting that a hotkey changed in game, it writes the new value in place of default, so that setting no longer follows Defaults.ini in this game until you set it to default again.

Defaults.ini is %AppData%\CameraUnlock\Defaults.ini on Windows; $XDG_CONFIG_HOME/CameraUnlock/Defaults.ini on Linux, or ~/.config/CameraUnlock/Defaults.ini where XDG_CONFIG_HOME is not set, under Wine and Proton too; and ~/Library/Application Support/CameraUnlock/Defaults.ini on macOS. The mod's log, where it writes one, names the file it read.

When the mod starts and finds no Defaults.ini, it creates one holding the built-in values, unless Windows runs the game as a packaged app. The mod never changes Defaults.ini after that. Edit it with any text editor.

The built-in value of each setting set to default below:

  • UdpPort=4242
  • EnableOnStartup=true
  • WorldSpaceYaw=true
  • RotationEnabled=true
  • LocalSmoothing=0.0
  • RemoteSmoothing=0.15
  • PositionEnabled=true
  • PositionLimitX=0.3
  • PositionLimitY=0.2
  • PositionLimitYDown=0.2
  • PositionLimitZ=0.4
  • PositionLimitZBack=0.1
  • ToggleKey=End, Ctrl+Shift+Y
  • CycleTrackingModeKey=PageUp, Ctrl+Shift+G
  • YawModeKey=PageDown, Ctrl+Shift+H
  • LightMultiplier=1.5

With every setting at its default, the file reads:

; Half-Life 2 head tracking settings.
; Comments start with ; and go on their own line. Text after a value is part of the value.
; Hotkeys are key names such as End, PageUp or Ctrl+Shift+Y. Separate several with commas; leave empty for none.
; A setting set to default takes its value from Defaults.ini, which every head tracking mod
; that keeps its settings in CameraUnlock.ini reads: %AppData%\CameraUnlock\Defaults.ini on
; Windows, $XDG_CONFIG_HOME/CameraUnlock/Defaults.ini (normally ~/.config/CameraUnlock) on
; Linux, under Wine and Proton too, and ~/Library/Application Support/CameraUnlock/Defaults.ini
; on macOS. The log names the file it read. Change a setting in Defaults.ini to change it in
; every game that has it set to default, or write a value here instead of default to change it
; for this game only.

[CameraUnlock]
; Written by the mod. Leave this section in place.
ConfigFormat=1

[Network]
; UDP port the mod receives tracker data on (OpenTrack protocol).
UdpPort=default

[General]
; true: head tracking is on when the game starts. ToggleKey turns it on and off.
EnableOnStartup=default
; true: yaw turns around the world's up axis. false: around the camera's own up axis.
WorldSpaceYaw=default
; true: turning your head turns the view.
; Tracking mode at startup, with PositionEnabled. The mode hotkey changes both.
RotationEnabled=default

[Smoothing]
; Smoothing when the tracker runs on this PC. 0 is the least, 1 the most.
LocalSmoothing=default
; Smoothing when the tracker is another device on the network, such as a phone.
; 0 is the least, 1 the most.
RemoteSmoothing=default

[Position]
; true: moving your head moves the view.
; Tracking mode at startup, with RotationEnabled. The mode hotkey changes both.
PositionEnabled=default
; How far, in metres, leaning left or right can move the view.
PositionLimitX=default
; How far, in metres, raising your head can move the view.
PositionLimitY=default
; How far, in metres, lowering your head can move the view.
PositionLimitYDown=default
; How far, in metres, leaning forward can move the view.
PositionLimitZ=default
; How far, in metres, leaning back can move the view.
PositionLimitZBack=default

[Hotkeys]
; Turns head tracking on and off.
ToggleKey=default
; Changes the tracking mode: rotation and position, rotation only, position only.
CycleTrackingModeKey=default
; Switches yaw between the world's up axis and the camera's own (WorldSpaceYaw).
YawModeKey=default

[Light]
; How far the light turns for each degree your head turns.
; 1 matches the view, 0 keeps the light on your aim.
LightMultiplier=default

[View]
; Field of view in degrees, as the game's fov_desired: horizontal, at 4:3, and the mod
; widens it for your screen as the game does. 0 leaves the game's own. Otherwise 30 to
; 150, which fov_desired's own 75 to 120 does not bound. A zoom still narrows the view by
; the factor it always did. Applies only while head tracking is on.
Fov=0.0
; Field of view the weapon in your hands is drawn with, in the same degrees. A wider Fov
; leaves the weapon looking oversized: lower this to shrink it. 0 leaves the game's own.
FovViewmodel=0.0

[Debug]
; true: write HeadTracking.log beside hl2.exe, new at every launch, with the launch before
; kept as HeadTracking.prev.log. It records the game build, the tracker connection and
; the view the mod draws. Attach it to a bug report.
LogToFile=true

Fov accepts 30 to 150, or 0 for off, and is applied as a ratio against your current FOV rather than written flat over it, so weapon zooms, the suit zoom and scripted camera moves still work and scale by the same factor.

The settings are read once at startup, so restart the game after editing the file.

Troubleshooting

Read HeadTracking.log, next to hl2.exe, first. It is rewritten from empty every launch, so it holds the session you just played and nothing older; the launch before it is kept as HeadTracking.prev.log, which is where a crashed session ends up once you relaunch. The log records the client fingerprint and discovery result, whether the hooks installed, the tracker connection and which smoothing is in force. Attach it to a bug report.

Mod not loading (no log file at all)

  • Confirm winmm.dll is in <game>\Half-Life 2\bin\, not next to hl2.exe. Source only loads DLLs out of bin\.
  • Confirm you took the x86 Ultimate ASI Loader. The x64 build cannot load into a 32-bit process.
  • Confirm HalfLife2HeadTracking.asi is in that same bin\ folder, spelled as shipped, and that LogToFile under [Debug] in CameraUnlock.ini has not been set to false.

Log says discovery was rejected

  • A required function, layout or live interface could not be validated. Keep the specific rejection message from HeadTracking.log and check the Releases page for an update.
  • The standalone Episode One (app 380), Episode Two (app 420), Lost Coast and Deathmatch campaigns are outside this mod's supported routes. Play the episodes inside app 220's hl2_complete campaign.

No tracking response

  • Check the tracker is running with its output set to UDP 127.0.0.1:4242, and that your firewall is not blocking that port.
  • Press End (or Ctrl+Shift+Y) to toggle tracking on, and check EnableOnStartup in CameraUnlock.ini has not been set to false.
  • If the log says UDP port 4242 busy, receiver will retry in background, another app is holding the port. Close it and keep playing; the mod retries twice a second.

Jittery or unstable tracking

  • Raise RemoteSmoothing in CameraUnlock.ini if the tracker is a phone or another device on the network, or route it through OpenTrack so its filters can clean the feed up.
  • For webcam tracking, improve the lighting on your face.
  • If the view flicks between two positions, two apps are both sending to port 4242. The log names both addresses; close the one you are not using.

Leaning or turning moves the view the wrong way

  • The mod applies the head pose as your tracker sends it, with no inversion of its own. Flip the axis in your tracker app.
  • If yaw feels wrong only when looking steeply up or down, toggle between horizon-locked and camera-local yaw with Page Down (or Ctrl+Shift+H).

Updating

Download the new release and run install.cmd again. Your settings in CameraUnlock.ini are kept.

Uninstalling

Run uninstall.cmd. This removes the mod DLLs and its log files, and leaves CameraUnlock.ini in place, so a reinstall keeps your settings. The mod loader (Ultimate ASI Loader) is only removed if the installer put it there. Use uninstall.cmd /force to remove it anyway.

Building from Source

Requires pixi, CMake 3.20 or newer, and Visual Studio with the x86 C++ toolset. Half-Life 2 is a 32-bit process, so the build targets Win32.

git clone --recursive https://github.com/itsloopyo/half-life-2-headtracking.git
cd half-life-2-headtracking
pixi run build-release
pixi run test
pixi run package

pixi run package produces the installer and Nexus ZIPs in release\. No copy of the game is needed to build.

Community & Support

  • Discord: Loop's Head Tracking Hangout - setup help, bug reports, and new-release announcements
  • Lopari - free Windows launcher with one-click install and launch for the released head-tracking mods
  • Headcam - free app that turns your iPhone or Android phone into the head tracker

License

MIT License - see LICENSE for details.

The mod statically links and redistributes third-party components under their own licenses. Each is listed with its version and full upstream notice in THIRD-PARTY-NOTICES.md, and both release ZIPs carry LICENSE and THIRD-PARTY-NOTICES.md alongside the binary. The demo clip at the top of this page contains Half-Life 2 footage, which remains the property of Valve and is not covered by the MIT license above.

Credits

Disclaimer

This mod is not affiliated with, endorsed by, or supported by Valve. It requires a legitimately purchased copy of the game. Use at your own risk.

About

An OpenTrack compatible head tracking mod for Half Life 2

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages