Development Changelog

What shipped, when, and why — the public record of PassthroughForge's evolution.

v2.66Multi-source tabbed kneeboard masks

v2.65 added four DCS auto-source modes (Aircraft, Theater, Mission, Briefing) but each mask could only pick one. v2.66 lifts that constraint: a single mask can carry any combination of sources as tabs, rendered in VR as a clickable-style strip across the top of the mask. One cockpit panel, four content streams, switchable with a HOTAS button.

What the editor looks like now

The single Auto-source dropdown is gone. In its place: one checkbox per source, each showing a live page count next to it. Tick as many as you want. When two or more are ticked, a set of Active tab radio buttons appears for switching the desktop preview, plus a Show tab strip in VR toggle for the in-headset overlay.

What the mask looks like in VR

┌───────────┬──────────┬──────────┬──────────────┐
│ Aircraft  │ Theater  │ Mission  │  Briefing    │   ← tab strip
│  3 of 8   │  2 of 4  │  5 of 45 │   1 of 7     │
├───────────┴──────────┴──────────┴──────────────┤
│         (active tab's page content)            │
└────────────────────────────────────────────────┘
  • Active tab highlighted blue with bright white text.
  • Page counter ("X of N") under each tab, updates live as you flip pages within the active tab.
  • Strip height scales with mask size (~8% of mask height, capped). Font scales with strip height. Atlas is baked in size-buckets so you only pay the bake cost once per mask-resolution class.
  • Per-tab page memory. Switching to Briefing on page 4, then over to Mission, then back to Briefing — you land back on page 4. Each tab remembers its own position.
  • Empty tabs don't disappear. A source with zero pages (e.g. a stock .miz with no baked KNEEBOARD/IMAGES/) still shows its tab, plus a subtle "(no content for this source)" hint in the page area so you can navigate away.

New shortcuts

  • Next Kneeboard Tab — cycle forward through the active mask's enabled sources.
  • Previous Kneeboard Tab — cycle backward.

Both are edge-triggered, always-active (work in tray mode with DCS in the foreground), and rebindable to keyboard / HOTAS / hat-switch directions like every other action. The recommended setup most testers end up with: Hat-Left / Right for tab cycle, Hat-Up / Down for page cycle. Two-dimensional kneeboard navigation without lifting the headset.

Profile compatibility

The mask format now persists an array of enabled sources, activeAutoKneeboardSource, and showAutoKneeboardTabs. Profiles saved by v2.65 (single source as a string) are auto-migrated to the new format on load — the old source becomes a one-element vector, no behavioural change. Single-source masks also still emit the old field so older PassthroughForge builds can read v2.66 profiles correctly.

Full step-by-step in the manual. The per-aircraft profile auto-switch from v2.65 still works on top of this — slot into a different jet and your whole multi-tab layout swaps to the matching profile.

v2.65DCS Auto-Kneeboard + Profile Auto-Switch

The biggest DCS-integration push since the original chroma-key cutout. Four new per-mask auto-source modes turn any mask into a live page view onto the DCS content ecosystem — without you having to drop a single image into the editor.

Auto-source modes (per mask)

  • DCS Aircraft — pages auto-populate from Saved Games\DCS\KNEEBOARD\<aircraft>\. Slot into a Hornet, your Hornet charts appear; switch to a Hog, they swap automatically. Works with everything you've already dropped into your KNEEBOARD folder, no migration needed.
  • DCS Theater — same idea, scoped to the loaded map (KNEEBOARD\Caucasus\, \Syria\, …). Useful for theatre charts that stay relevant across multiple aircraft.
  • DCS Mission (.miz) — the active mission file is unzipped on the fly and its KNEEBOARD/IMAGES/ baked-in pages are loaded. Cached per mission so re-loading the same .miz is instant. Compatible with the standard DCS Mission Editor kneeboard workflow.
  • DCS Briefing (rendered) — the mission Lua table is parsed and rendered to paginated A4 PNGs. Includes Sortie, Mission (theatre + start), Your Flight (callsign + frequency), Bullseye, full numbered waypoint list with altitude (m / ft) and speed (kts), AI assets (AWACS / Tankers / CAP / SEAD / CAS with frequencies), the mission briefing prose, per-coalition tasking, and weather (QNH in 3 units, temperature, wind at 3 altitudes, clouds, visibility, fog).

Profile Auto-Switch on aircraft change

Each profile now has an optional Default for aircraft field. When the DCS hook reports a slot change to a matching aircraft, PassthroughForge loads that profile automatically. Combined with the Auto-source modes above this means: hop from your Hornet into the Hog mid-mission, your entire mask layout swaps and your charts swap, one trigger, zero clicks. OpenKneeboard requires user-written Lua to get this; in PassthroughForge it's a one-field setting.

Smaller things in this release

  • DCS GUI hook extended to forward aircraft type (from LoGetSelfData()), theatre name, mission file path (absolutified against the DCS install root), and Saved Games path on every mission load and slot change. Loopback UDP only, MP-safe (lives in Scripts\Hooks\ like before).
  • New module: MizExtractor — shells out to %WINDIR%\System32\tar.exe (libarchive, ships with Windows 10 v1803+) to unzip .miz files. FNV-1a-keyed cache under %TEMP%\PassthroughForge\miz-cache\ reuses the extraction folder when the .miz hasn't changed.
  • New module: LuaTableParser — a ~300-line recursive-descent parser for the Lua data subset DCS uses (tables, strings, numbers, booleans, nil, line comments). Zero external dependencies.
  • UTF-8 normalisation for briefing text — smart quotes, em-dashes, ellipses, bullets and arrows are mapped to their ASCII equivalents before being rendered. Fixes the previously visible "DonâBBt" garbling for typographically rich mission descriptions.
  • Section-aware pagination — the rendered briefing keeps each section together on one page where it fits, and splits long sections only at paragraph boundaries. No more orphan headings.
  • Frequency-format heuristic — the Lua table's frequency field is interpreted as MHz when small (137.4), as Hz when large (251000000). Zero is treated as “mission uses aircraft preset” and the line is omitted.

How to use it: install v2.65, run the installer once so the new DCS GUI hook lands in your Scripts\Hooks\. In the editor, set any mask's Auto-source dropdown to one of the new DCS Aircraft / Theater / Mission / Briefing modes. For profile auto-switch, type the DCS aircraft ID into a profile's Default for aircraft field (or click "Use 'current aircraft'" while DCS is running) and enable Auto-switch profile on DCS aircraft change in Settings. Full walkthrough in the manual.

v2.64Mask Lock pose-jitter filter

Removes the small "swimming" of Mask Lock masks that occurred when a controller was resting in the cockpit. Quest 3 controllers ship bursts of ~1–5 mm IMU position drift each time they wake out of standby; before this build, those bursts propagated 1:1 into the locked mask and were visible as a slow drift.

  • 5-tap median filter on controller position for Mask Locker modes only. Drift bursts of up to two consecutive outlier samples are rejected completely while real user motion (active controller movement) still passes through with about 28 ms lag — not perceptible.
  • Validated with a new layer-side telemetry log (%APPDATA%\PassthroughForge\logs\PassthroughForge_SwimDiag.log). Measured before/after on the same scene: peak quad-pose drift dropped from 4.88 mm per frame to 0.34 mm (-93 %), average drift from 23 µm to 1 µm.
  • Regular controller-tracked masks unchanged. Only Mask Locker uses the filter; in the active-grip mode where you swing a mask around, raw controller pose is still used so the mask tracks the controller with zero added latency.

Validated tip for the head-motion swim: a separate "mask lags during fast head turn" effect can still appear when DCS frame-time stutters under heavy mission load. Tester confirmation: lowering the VR render resolution one notch eliminates this completely. Once DCS holds a stable frame rate, the compositor's late-stage reprojection of the mask quad keeps it locked to the cockpit. Full troubleshooting and settings guidance in the manual.

v2.63Enhanced Diagnostics + Region Capture Quality

Better insight into customer setups and usage patterns, plus sharper and smoother Screen Region Capture.

  • Region Capture quality — captured regions are now passed at full resolution to the GPU, which handles downscaling with bilinear filtering. Eliminates staircase artifacts on lines and text that appeared when the mask was smaller than the captured region.
  • Capture refresh rate — default raised from 30 Hz to 60 Hz for noticeably smoother updates.
  • System info at startup — the app log now records Windows version, CPU core count, RAM, GPU name, VRAM, driver version, and Direct3D feature level on every launch.
  • UI interaction tracking — key button clicks (Add Mask, Import/Export, Window/Region capture, Profile save, etc.) are logged with timestamps for usage analysis.
  • Window foreground tracking — logs when PassthroughForge gains or loses focus, helping diagnose background-mode issues.

v2.62Screen Region Capture

New mask source: capture any rectangular region of any monitor and stream it live into a VR mask. Ideal for DCS DDI/MFD export or any desktop instrument panel.

  • Screen Region Capture — new + Region… button opens a dialog to select a monitor and define a pixel region (X, Y, Width, Height). The region is captured via Windows.Graphics.Capture (WGC) with GPU-side cropping and streamed into the mask at the configured refresh rate.
  • DCS DDI export workflow — combine a DCS MonitorSetup.lua that renders MFCDs to the desktop with Region Capture masks to display cockpit displays (left DDI, right DDI, AMPCD) in VR.
  • Monitor enumeration — uses physical pixel resolution (unaffected by Windows DPI scaling) so coordinates match what WGC actually captures.
  • Profile persistence — region masks (monitor index + coordinates) are saved/loaded with profiles and auto-reconnect on launch.

v2.61Global Offset + new-mask spawn fix

Two fixes for the Global Offset system that caused confusion and diagonal mask movement after Recenter or Mask Locker events.

  • Global Offset Euler sliders now stay in sync. The G.Pitch / G.Yaw / G.Roll display could show stale values after Recenter All Masks, Reset Snap, or a Mask Locker auto-recenter. Accidentally dragging one of those stale sliders would write the old rotation back into the quaternion. The sliders now detect external quaternion changes every frame and re-decompose automatically.
  • New masks spawn correctly when Global Offset is active. Creating a mask via “+” while a non-identity rotation offset was in effect (e.g. after Mask Locker) placed the mask in a rotated coordinate frame. Subsequent per-mask X slider drags would also move the mask along Z. The spawn code now uses the full inverse layer transform (matching Face Me) so per-axis editing stays clean.

v2.60MSFS 2024 support + mask-tab shortcuts

PassthroughForge now works with Microsoft Flight Simulator 2024 and any other DirectX 12 OpenXR title. Plus new shortcuts to cycle through mask tabs without reaching for the mouse.

  • Microsoft Flight Simulator 2024 / DirectX 12 support. The OpenXR API layer now detects D3D12 graphics bindings and automatically creates a D3D11-on-12 interop device. Masks, textures, and shared-memory rendering work exactly as in D3D11 titles (DCS World, MSFS 2020, etc.) — no user configuration needed.
  • Select Next Mask / Select Previous Mask shortcuts. Two new fully-bindable actions that cycle through the mask tab bar. Default bindings: Ctrl+Tab (next) and Ctrl+Shift+Tab (previous). Wraps around at both ends. Works in foreground, tray mode, and background — rebindable to any keystroke or HOTAS button via Settings → Mask Shortcuts.

v2.59Tester bug-fix round — Q/E in DCS, installer args, bindable mask toggles, axis-aware sliders

Several fixes from the latest tester round, bundled into one drop so you only have to swap the EXE once.

  • Position sliders are now true world axes. Tester report: dragging the X slider on a mask facing the player also moved the mask along Z — pure left/right editing turned into a diagonal slide. Cause: the sliders projected world coordinates through cos/sin(headYaw) before display, so any head rotation made the visible "X" axis diagonal in world space. Fix: sliders show + edit pure world coords (matching the keyboard shortcuts, which were already world-axis by deliberate design). Section header renamed to Position (world axes) with a helper line spelling out the convention (X = right, Y = up, Z = back). Predictable regardless of where you happen to be looking.
  • Auto-save shortcut bindings. Rebinds, Clear, and Reset to Defaults now write to disk the moment they happen instead of waiting for the Shortcuts window to close. A crash or task-kill between rebind and window-close can't silently lose your changes anymore.
  • Start with Windows tickbox in the settings menu. First-class in-app toggle so you can flip autostart any time without re-running the installer. The installer also got smarter: answering "n" to its autostart prompt now actively removes any leftover entry from previous installs, so "no" really means no.
  • Running version visible in the app. Window title and the top-left of the menu bar both show PassthroughForge v2.59 so you always know which build you're on without digging through Programs & Features.
  • Q and E (and any other bare-key shortcut) now reach DCS again. A tester reported that mapping Q to a PassthroughForge action silently disabled DCS's own Q binding (rudder / brake / whatever). Cause: the global keyboard hook swallowed the keystroke after firing the PF shortcut. Fix: bare-key bindings (no Ctrl/Shift/Alt) now fire the PF action AND pass the key through to the foreground sim so DCS sees it too. Modifier-bound shortcuts (Ctrl+Q etc.) keep their previous exclusive behaviour — if you picked a combo deliberately for PF, it stays PF-only.
  • Installer -Uninstall argument is honoured. Running powershell -File install.ps1 -Uninstall from a non-admin shell silently fell through to a fresh install instead of uninstalling. The script self-elevates with -Verb RunAs but was launching the elevated child without forwarding the original switches. Fix: every parameter / switch from $PSBoundParameters is now forwarded to the elevated process, so -Uninstall (and any future flag like custom -InstallDir) survives the elevation.
  • Toggle Mask 1…8 and Toggle All Masks are now fully bindable. Previously these lived as hard-coded Ctrl+F1..F8 / Ctrl+F9 combos in the keyboard hook — you couldn't move them to a HOTAS button or to a different key. Tester request: bind Toggle All Masks onto a stick button for instant on/off without taking the headset off. Fix: nine new rows in the Shortcuts panel, defaults still Ctrl+F1..F9 so existing muscle memory works, but each row now has a Rebind button just like every other shortcut. Joystick / hat bindings work too. Mask toggles also fire even when DCS isn't the foreground app, so you can flip masks while testing the layout from the desktop.
  • Recenter All Masks now uses a rigid-body transform. Tester report: after pressing Recenter, dragging a position slider also moved the mask diagonally; adding a new mask afterwards landed it in the wrong place; multiple Recenter presses didn't compose the way you'd expect. Root cause: the old recenter stored its result in a running global offset that the layer re-applied every frame, leaving the world frame rotated relative to your view. Fix: each Recenter now computes the delta from the previous Recenter's head pose and applies that same translation+yaw to every world-anchored mask as a single rigid body. Inter-mask spacing is preserved exactly, the global offset stays at 0/identity, newly-added masks spawn where you're looking, and stacking Recenters behaves like one absolute snap to current view. Reset Snap still undoes everything from the session back to the original profile layout.
  • 3D position preview matches what you see in VR. The little 3D wireframe under the Position sliders used to draw masks from their raw stored coordinates, which after a Recenter looked rotated/offset relative to the actual VR-rendered position. The preview now runs the same forward transform the layer does, so the wireframe, the slider numbers, and the headset all show the same pose. Useful for fine-positioning without taking the headset off.
  • Controller tracking on exotic OpenXR stacks. Two fixes for testers whose Mask Lock showed red "0.00" coords: (1) when the host app suggests interaction-profile bindings for only one controller profile (e.g. khr/simple_controller) while the runtime activates a different one (e.g. oculus/touch_controller), the layer now self-suggests grip-pose bindings for the common controller profiles the app skipped, so our pose action always has a binding for whatever profile the runtime picks. (2) Instance-aware action lifecycle: on multi-layer setups where a new XrInstance gets created after the layer's first one, the cached action handles used to return XR_ERROR_HANDLE_INVALID; we now detect the instance change and rebuild the action set fresh so attach + xrLocateSpace work normally.

No data migration needed — profile format and settings.json are unchanged. Drop in the new EXE + Layer DLL and re-launch.

v2.58Add/Subtract draw mode + editor-only mask transparency

Two editor-side tester requests, both shipped together because they're complementary — one makes complex shapes possible, the other makes them tidy.

  • Add / Subtract draw-mode toggle. A new pair of radio buttons in the Drawing Tools row. Add (default, green) is the existing "fill with passthrough colour" behaviour; Subtract (red-orange) flips every painting tool into a clearing tool:
    • Brush + Subtract = erase along the stroke
    • Rectangle + Subtract = clear the dragged bbox — instant rectangular hole-puncher
    • Polygon + Subtract = cut a polygon-shaped hole, with the live edit preview honouring the mode
    • Fill + Subtract = bucket-erase the connected region
    Use case from the request thread: filled rectangle outside, Subtract rectangle inside → instant frame in two clicks. Same idea works with polygons for non-rectangular cutouts. The standalone Eraser tool stays as a quick-access preset for users with muscle memory.
  • Mask α slider in the View card. Editor-only mask transparency on the canvas (0.05–1.0 with a "100%" reset button). Drop it below 1.0 and the mask becomes semi-transparent in the editor so the reference image (or any canvas-only background) shows through while you paint — the difference between guessing edges and tracing them. Crucially editor-only: the mask in your headset stays at its real opacity regardless of where the slider sits. Saved profiles, SHM state, layer rendering: all unaffected.

Backwards-compatible: settings.json schema unchanged, profile format unchanged, layer DLL unchanged. Just open a profile from v2.57.x in v2.58 and the new controls are right where you'd expect them.

v2.57.4One PassthroughForge at a time — no more mask flicker from accidental double-launch

Issue: several testers reported masks flickering while setting them up. Investigation traced it to PassthroughForge being launched twice — the user double-clicked the desktop icon when the first instance was already minimised to tray, ended up with two PF processes running side by side, and both fought over the same shared-memory channel that drives the OpenXR layer. The result: every other frame each instance overwrote the other’s mask state, producing the flicker.

Fix: a process-wide single-instance guard. The first PassthroughForge launch claims a named mutex; any subsequent launch detects the mutex, finds the existing window, restores it from tray if needed, brings it to the foreground, and exits silently. No error popup, no scary dialog — you double-click the icon and PassthroughForge appears, whether the first instance was visible, hidden behind another window, or minimised to tray.

Net effect: it is now impossible to run two PF processes against the same Windows session. The flicker is gone. The only behaviour change you’ll notice: a second click on the launcher pulls up the existing instance instead of starting a fresh one.

v2.57.3Modifier-less shortcuts no longer steal keys system-wide

Issue: if you bound a mask shortcut to a single key without modifiers (the default Q / E for Fine / Coarse step toggles, or any custom binding like F for Recenter), that key became unusable in every other Windows application as long as PassthroughForge was running. Typing in Notepad, the browser, Discord — the letter just wouldn't appear. Closing PF restored normal keyboard behaviour.

Cause: on tray-mode entry, PassthroughForge registered each shortcut binding as a Win32 global hotkey via RegisterHotKey. For combos with modifiers (Ctrl+Arrow, Ctrl+F1, ...) this is fine — nobody else uses those. But for a bare letter like Q or E, the API claims that key system-wide. Other apps stop receiving it until the registration is dropped. The low-level keyboard hook that handles tray-mode shortcuts already gates correctly on “is a flight sim in front?”, so the RegisterHotKey call was both redundant and harmful for these bindings.

Fix: modifier-less bindings now skip RegisterHotKey entirely. The LL hook continues to handle them — it dispatches them only when DCS / a known sim is foreground, and passes them through to whatever app you're typing in otherwise. No data loss, no settings migration; existing keyboard bindings keep working as before with the system-wide block lifted.

v2.57.2DCS Messages auto-clear on mission boundaries

Issue: the DCS Messages kneeboard never cleared between missions. Yesterday's chat, last sortie's mission triggers and previous flight's radio chatter all kept piling up on the same panel until the 200-line ring buffer rolled over. Hard to read at a glance during a fresh mission.

Fix: the DCS hook now sends an explicit clear signal on the two natural mission boundaries — onMissionLoadEnd (a new mission just finished loading) and onSimulationStop (player exited the mission, returned to main menu / debriefing / dropped a server). The desktop listener treats the signal specially: drops the entire buffer and re-renders the kneeboard mask empty.

Net effect: every new mission now starts with a clean DCS Messages panel. No manual button, no settings toggle, no per-profile config — the boundary is detected directly from DCS.

Required step after upgrade: the new PassthroughForge.lua hook script needs to land in your Saved Games\DCS*\Scripts\Hooks folders. Re-run the installer once and it'll redeploy the hook to every DCS profile it finds. Until that happens you'll keep getting the old “[mission loaded]” trigger message instead of the automatic clear.

v2.57.1HOTAS bindings now work in tray mode

Fix: in v2.57, joystick / HOTAS bindings stopped firing as soon as PassthroughForge lost foreground or was minimised to the tray — exactly when you actually want them to work while flying in DCS. Keyboard bindings were unaffected because they ride on a separate global Win32 hook.

Cause: the joystick poll loop ran inside the UI render path, which the main loop deliberately skips when the window isn’t in front (a power-saving / GPU-coexistence measure). With render skipped, no poll, no joystick events.

Resolution: joystick polling now runs in the main loop on every iteration regardless of focus or tray state. DCS sees the same button events for its own bindings (we still poll non-exclusively), so nothing changes for keyboard or for DCS coexistence — only the “works while minimised” gap is closed.

No settings.json migration needed; existing v2.57 bindings continue to work as-is.

v2.57HOTAS / joystick support for mask shortcuts

Direct response to beta-tester feedback: bind any of the 34 mask-shortcut actions to buttons or hat-switches on arbitrary HOTAS hardware — the same way you bind keyboard combos today. Stick, throttle, rudder pedals, generic joysticks: all treated equally.

  • Buttons + hat-switches: bind any action (move, rotate, scale, recenter, page next/prev, ...) to a joystick button or a hat direction. Hat-switches are edge-triggered for navigation actions, held-continuous for movement — same semantics as keyboard.
  • Universal device support: based on SDL2's joystick subsystem, so anything Windows recognises as a HID joystick works. Tested with Thrustmaster Warthog, T.16000M, Virpil, VKB, generic stick + throttle combos.
  • Stable bindings across reboots: devices are identified by SDL GUID (vendor + product + version hash), not by USB-port order. Move your throttle from one port to another and bindings still work.
  • Hot-plug: unplug a device mid-session, bindings on it become no-ops cleanly. Replug the same device and they wake up again automatically.
  • Coexists with DCS: PassthroughForge polls in non-exclusive mode, so DCS receives the same button events for its own bindings. The same physical button can drive a PF mask AND a DCS in-cockpit action simultaneously.
  • Tray-mode-friendly: joystick polling works regardless of which window has focus, so HOTAS shortcuts fire through the tray-icon mode just like keyboard shortcuts do.
  • Unified rebind UI: hit "Rebind" on any action, then press EITHER a key OR a joystick button — first input wins. The binding-column display reads "Joy[Warthog Throttle] Btn 7" or "Joy[VKB Stick] Hat1 Up".
  • Backward-compatible: existing v2.56 keyboard-only settings.json files load without warnings or data loss. The schema gains an "src" discriminator so future input types (analog axes, MIDI, ...) can extend without breaking earlier files.

Out of scope for this release: analog axes (throttle position, stick X/Y as continuous input). Coming in a follow-up release with proper deadzone / threshold UI.

v2.5630-day trial & clock-tampering protection

The licensing model has been reworked to give beta evaluators a proper time-based window instead of a launch counter, with a tamper-resistant clock anchor underneath.

  • 30-day trial replaces the 5-launch limit. The trial banner now reads “Trial: N days remaining”, switching to hours / minutes on the last day. The launch counter is still shown alongside as informational context, but no longer affects expiry.
  • Clock-tampering detection (ClockGuard). A new module maintains a redundant high-water mark of the highest UTC time the app has ever observed, persisted in %APPDATA%\PassthroughForge\.sentinel and in the registry. If the system clock is rolled backward, the trial is blocked for that run with an explanation dialog. Forward jumps larger than one day are not trusted as new references, so a corrected clock cleanly resumes the trial.
  • Fair, not punitive. A flat CMOS battery, a forgotten BIOS reset, or an NTP correction won’t kill your trial — correct your system clock, restart, and the remaining days are still there. A valid activation code works regardless of clock state.
  • Migration is automatic. Existing testers upgrading from v2.55 or earlier get a fresh 30-day window starting from the upgrade run — no manual reset needed.

Underlying file format and UI text changed accordingly; the “trial expired” dialog now distinguishes time-based expiry from clock-correction prompts.

v2.55Mask Locker keep-alive verified

A small but hard-won release: stabilising the Mask Locker controller-binding feature against Quest 3 / Virtual Desktop’s controller standby behaviour.

  • Keep-alive haptic pulse: every ~12 s (900 frames at the typical Quest+VD framerate) the layer sends an imperceptible 1 ms / 1% amplitude vibration to any controller hosting a Mask Locker mask. The pulse keeps the controller’s internal IMU and IR LEDs awake instead of dropping into power-save standby after a quiet stretch.
  • Verified in flight: linker controller stayed continuously tracked over a 3+ minute test (frame 11 700→18 900) with nine keep-alive pulses logged at perfect 12 s intervals, surviving a runtime reference-space rebase storm in the middle.
  • Manual updated with a new troubleshooting section explaining why a Mask Locker mask can still drift if the Quest cameras can’t see the controller, plus the proximity-sensor tape tip that prevents playspace shifts when you flip the headset up to look at the screen.

v2.46DCS Messages mask

A new mask type that displays DCS in-game messages — multiplayer chat, mission trigger texts, AI radio chatter — on a freely placeable A4 panel inside your cockpit.

  • Lua hook: a 30-line script in Saved Games\DCS\Scripts\Hooks\PassthroughForge.lua forwards in-game messages over loopback UDP (127.0.0.1:31090). Nothing leaves the PC.
  • Installer integration: a new [3.5/5] step finds every Windows user profile with a Saved Games\DCS folder and drops the hook into place. Uninstaller removes it again.
  • Player-only filter: outbound radio calls (lines starting with Spieler: / Player:) are hidden so the panel only shows traffic addressed to you.
  • Settings menu → DCS Messages (Beta)…: a debug feed that confirms the hook is delivering messages, with a live counter and a Clear button.

See Manual → DCS Integration for setup details and manual install instructions.

v2.45Beta backend & polish

  • Beta signup pipeline: signup form → MySQL DB → admin approval → tokenised one-shot download URL.
  • SMTP-AUTH email delivery: replaced PHP mail() with a custom STARTTLS + AUTH LOGIN client so beta-approval mails actually arrive.
  • GDPR / DSGVO: full privacy policy page, opt-in disclaimer on the signup form, CSV backup export tool.
  • Profile UX: + New creates a blank profile instead of duplicating the current one.
  • Installer hardening: post-install verification step reads back the registry key and prints a checklist before launching.
  • Stream Deck profile: ready-made profile + landing-page download for one-button mask control.
  • Manual: Troubleshooting section covering chroma-key bleed, edge halo, and "layer not loaded" cases.
  • tools/deploy_local: one-click developer helper that drops fresh build outputs into the install dir without rerunning the installer.

v2.44Startup polish

  • Eliminated the blank-window / un-painted-canvas flash on startup.

v2.43Background shortcuts

  • Shortcuts continue to fire when PassthroughForge runs behind DCS or another VR app, even without tray mode. Low-level keyboard hook is now always-on instead of tray-only.

v2.42Tab-bar UX

  • New mask is auto-selected on creation; active tab uses a green accent so the current mask is obvious.

v2.41Window Capture

  • Major feature: Windows.Graphics.Capture integration. Any top-level window on your desktop can become a mask — Discord, Telegram, charts, browser tabs, even another DCS instance.
  • Window picker modal with live thumbnails.
  • Configurable refresh rate (5–240 Hz) per session.
  • Auto-rediscovery: profile reload finds the right window again as long as the title pattern matches.

v2.40Recenter All Masks

  • OpenKneeboard-style head-anchored snap: rigidly rotate the entire mask group around your head so its centroid bearing matches your forward direction. Distances and heights preserved. Profile data is never touched — Settings → Reset Snap undoes everything.

v2.30–v2.39Tracking, rotation, math

  • v2.39 Per-mask + global keyboard translate use fixed world axes (no head-yaw mixing) so Ctrl+arrows behave predictably.
  • v2.38 Per-mask rotation: drift-free base + Euler model with a Face Me reset.
  • v2.37 Reverted v2.36's global-offset-applied-to-tracked-masks after it caused jitter on controller-tracked panels.
  • v2.36 Global Offset keyboard shortcuts.
  • v2.35 Trace VR passthrough follows newly added masks instead of staying on the previous selection.
  • v2.34 Haptic wake-up pulse for Mask Locker after a recenter, so the controller exits standby.
  • v2.33 Mask Locker: controller-tracked masks with deferred binding — pick the controller while it's asleep, the conversion happens once it wakes up.
  • v2.32 Auto-Face-Me on Trace VR; redundant Snap buttons removed.
  • v2.31 Recenter button moved to the menu bar; ASCII-clean strings throughout for cross-locale safety.
  • v2.30 Pivot-based Snap to View; profile-clean recenter (transforms never modified).

v2.20–v2.29Tray mode, hotkeys, polish

  • v2.29 Canvas zoom performance; system-wide hotkeys via low-level hook.
  • v2.28 Polygon drag perf: skip mirror fill, cheaper bezier tessellation.
  • v2.27 Tray-mode polish: game-only LL hook, X quits cleanly, blue default chroma.
  • v2.26 Cross-process keyed mutex (no more torn reads); Color Anti-Bleed; Fine x0.1 step mode.
  • v2.25 Configurable mask toggle fade (default instant).
  • v2.24 In-VR cheat sheet for keyboard shortcuts.
  • v2.23 LL keyboard hook so tray-mode shortcuts work while DCS has focus.
  • v2.22 Tray mode + global shortcuts; step-mode toggle; None tool.
  • v2.21 Endless drag for sliders; configurable mask shortcuts.

v2.0Foundations

  • Canvas scaling, Recenter to Player, snap bugfixes, UX polish — the inflection point where the editor became something you'd actually use in a session.
  • v1.9 Controller tracking, Gaze Activation, Mirror Mode, full UI overhaul.

v1.xOrigins

  • v1.0–1.4 First public release, polygon mirror mode, mask rename.
  • v0.x (pre-1.0 history) The early features that seeded the toolkit:
    • Apple-Glass UI overhaul, live drag preview, 4K defaults.
    • Polygon live-fill, Add/Replace toggle, polygon additive mode.
    • Rectangle tool, 3D model import (STL + FBX) with orthographic presets, reference images.
    • Undo/redo, mask grouping with group toggle, grid overlay + snap-to-grid for polygon, global hotkeys.
    • Profile dropdown, auto-start with last profile, PNG export.
    • Bezier curves for polygon, isometric 3D preview, eye-visibility toggles.
    • Global rotation offset, tab sync, chroma-key color presets.
    • STAGE reference space, global recenter offset, auto-load profile.