HydraIssues

MASTER: hydragon MVP - one map, Serath playable in VR, all other heroes NPC
open feature Priority: high Project: hydragon Reporter: cederik 31 Aug 2026 17:01

Description

Verified handoff 2026-09-15: native template on MSI1060

This update supersedes stale infrastructure/build assumptions below; earlier project decisions remain history.

  • Dedicated Hydragon Perforce and Unreal typemap are completed. Preserve them.
  • Reusable C++ Hydra Unreal Template compiles/cooks on UE 5.7.3. Native Linux build 2 is live in ExperienceLibrary for bxl1/ad6, organization experiencenet (Hydra ExperienceNet), and installed on MSI1060 (node-d71b197c, Omarchy/GTX1060).
  • Flat rendering and authenticated HydraBody launch are verified. On 2026-09-15 at 18:32:23 UTC, a fresh interactive flat run rendered the lit wordmark cube on the unlocked desktop, with no new Unreal errors or GPU Xids in follow-up. That user-requested session was left running. Full Hydragon gameplay is not implemented.
  • Chunky remains the intended Windows development machine. The Linux artifact does not establish a working Windows experience there; current UE 5.7.3 build readiness there remains unverified.
  • Source and rollout evidence, committed and pushed: https://github.com/cederikdotcom/hydraunrealtemplate/blob/master/docs/deployment-status.md (September 15 documentation commit efe2183). HydraBody PR #1 and HydraCluster PR #6 were merged; deployed body v2.0.70-rc.12 and cluster v2.0.116 verified during rollout.
  • A successful WiVRn stream of HelloHydra XR is separate from Unreal headset acceptance. New issue #741 specifically validates this template against the WiVRn build: stereo, 6DoF, full hands and loss/recovery, exact build provenance, sustained logs and flat regression. No runtime/headset changes made in this handoff.
  • New HydraMancer onboarding increment #742, under #490, teaches the verified template-to-body path. Source-submit automation remains #634. Library fresh-install regression #721 remains open; registering a live experience alone does not prove installation.

Goal

hydragon is the system seller for Hydra. It is a VR hero arena game, in the spirit of Epic's Paragon (https://www.unrealengine.com/paragon).

The MVP proves one loop, end to end: one map, one human player in VR as Serath, every other hero an NPC bot, streamed in 6DoF from a Hydra body to a headset.

VERIFIED STATE 2026-08-31. Read this before you plan anything.

A 14 agent reconnaissance ran on 2026-08-31. It measured the machines instead of assuming them. Several numbers in the sections below were wrong. The corrections are here, and they are the truth until someone measures again.

The hero is SERATH, not Seraph

There is no Paragon hero called Seraph. The hero is Serath. Every mention below is corrected. Searching Fab for "Seraph" returns nothing, so this would have stopped the first person who tried to download the asset.

Good news: hand tracking over the stream is close to solved

Risk 1 is much smaller than this issue claimed. ALVR 20.14.1, the version on chunky, already sends the full 31 bone hand skeleton to SteamVR. The OpenVR driver calls CreateSkeletonComponent on /input/skeleton/left and /input/skeleton/right and pushes real joint data on every SetTracking call. chunky's live ALVR session.json has hand_skeleton enabled and steamvr_input_2_0 true. It is not emulated controller poses only.

One link stays unproven: which ALVR device SteamVR binds to /user/hand/left, and whether xrLocateHandJointsEXT reports isActive true to an Unreal application. One small OpenXR probe settles it. That is still the Phase 0 spike, but it is now a confirmation, not an investigation.

Note: hand_tracking_interaction is OFF on chunky today, so ALVR sends joints but no gesture buttons. That is the correct setting for us, because we recognise our own gestures from joints.

Bad news 1: the build machine cannot build

chunky-turnip-23 was measured. It is an HP Z2 (hostname Sanctuary-AD6):

  • Free disk 113.6 GB total. 44.8 GB on C:, 69.7 GB on D:. The budget in this issue said 500 GB. Both disks are fully allocated with zero unallocated space.
  • D: is a mechanical hard drive, a WDC WD5000AAKS. The only solid state disk is C:, and C: is 90 percent full.
  • 15.7 GB of RAM, one 16 GB module in a four slot board. Unreal wants far more.
  • Unreal Engine 5.4.4 is installed, not 5.7. It uses 35.9 GB of D:.
  • No Perforce client. No p4 binary anywhere.
  • No Visual Studio, no MSVC, no Windows SDK, no dotnet. A C++ Unreal build is impossible today.
  • No Epic account is signed in. The launcher runs and logs SignedIn=0. Paragon assets need an interactive login.
  • WDAC user-mode enforcement is OFF, as claimed. That part was right.

Space is held by D:\Cederik (Steam, 261.4 GB), C:\Users (185.5 GB), D:\Edorble (39.0 GB), D:\Executxr (38.9 GB). Freeing space means deleting someone's data, so it is a human decision.

Bad news 2: the 200 GiB depot quota is not real

hydraskin-perforce-1 is a cx43 with one 152.3 GiB disk. Incus runs on a loop file btrfs pool capped at 106 GiB, with 29.4 GiB used, shared by every scale on the node. The existing quotas already over-commit it: galloromeinsmuseum 60 GiB plus p4scale-visitflanders 90 GiB, thin against 106 GiB.

You can set size=200GiB on a new scale. It will succeed and it will mean nothing. The pool fills about 76 GiB later. Per #543 a full quota wedges p4d's SSL listener, and because the pool is shared that takes Cyborn's live gallo scale and Soulmade's visitflanders down with it.

So: do not provision hydragon at 200 GiB on this node. Add storage first, or give hydragon its own node.

Bad news 3: the watcher publishes, it does not build

This is the largest scope discovery. hydraperforcewatcher is a publisher, not a builder. The chain is: you submit an already packaged Unreal build under Builds/, the watcher zips what that changelist touched, uploads it to hydramirror, and notifies hydracluster.

Nothing anywhere cooks or packages Unreal. "No manual copy" in this issue means no manual copy of a packaged build. It never meant automated cooking. Automated packaging does not exist in any repo and is unscoped work. Decide whether we want it before Phase 3, and file it if we do.

Other verified blockers

  • hydramirror has 2.52 GB free of 40 GB. A trivial proof artifact fits. A real Unreal package does not; the gallo builds are 5.3 GB each. Free space before Phase 2.
  • One watcher process serves one p4d server. The config has a single global perforce.port. hydragon on its own port needs a second watcher instance, with its own config, state directory, systemd unit and agent identifier. Editing the running config repoints Cyborn's watcher.
  • The build notification fails silently on any 4xx. The hydragon experience must exist in the library, with a matching watch name, BEFORE the first submit. Otherwise the library returns 404, the watcher logs a warning, marks the changelist processed, and the build is lost with no retry. Same shape as #609.
  • No Perforce typemap exists on any of our servers. Not on the old shared server, and ensure-server never sets one. Every scale starts with p4d's empty default, so .uasset files land by content auto-detect rather than by policy. This is a latent corruption and merge-conflict bug for every Unreal depot we run, not only hydragon.
  • manage_ufw is absent from the node configuration, so ensure-server will not open the new port. The scale would be created, the depot would exist, the tool would print a working-looking address, and nothing outside the node could reach it.
  • The ALVR driver is not registered on chunky right now. openvrpaths.vrpath points only at a Virtual Desktop path that no longer exists. Any probe or Unreal application launched today attaches to SteamVR with no headset and measures nothing.
  • No Pico headset exists in the fleet, and Pico documents hand tracking over streaming only on the Pico 4 Ultra Enterprise. The Pico half of the Phase 0 spike and all of #626 need that specific purchase.
  • Port 1668 is free and is the correct host port for a hydragon scale. 1666 is gallo, 1667 is visitflanders.
  • No hydragon repo or depot exists anywhere yet.

Corrected convention for the depot layout

The other Unreal depots agree: the Unreal project sits in a named subfolder of the stream, Builds/ sits beside it at stream root, and .hydrabuild.yaml sits at stream root, because the watcher reads <stream>/.hydrabuild.yaml literally. Runbooks and testbooks do NOT live in the depot. They live in the Go tooling repositories, split by audience.

Still unverified, needs a human

The Paragon Serath pack's supported engine versions. The reconnaissance claimed 4.19 to 4.27 and 5.0 to 5.8, but the page it saved carries no version text, so treat that as unverified. Fab blocks scripted reads. A human must open the Serath listing while signed in and read the supported versions. If the pack turns out to be 4.27 only, a UE4 to UE5 conversion pass appears in Phase 2 and Phase 3 that nobody has costed.

CORRECTION 2026-09-01: Unreal packaging DOES exist. It is hydraunrealengine.

The reconnaissance said "nothing in any repository cooks or packages Unreal". That was wrong. cederikdotcom/hydraunrealengine is exactly that tool: a native Windows Go binary that wraps RunUAT with preflight checks.

What it does:

  • hydraunrealengine package [project.uproject] --platform Win64 --config Shipping --output C:\Builds cooks and packages through RunUAT.
  • Preflight checks catch the known packaging traps before UAT runs: Live Coding, GameplayStateTree, Visual Studio, and Perforce state.
  • --deliver zips the result and uploads it to HydraTransfer.
  • It has a context system, a local web interface (serve), and self-update from the release server.
  • It already contains a pkg/p4 Perforce wrapper, so it understands our source of truth.

So the real gap is much smaller than stated. We are not missing a packager. We are missing the automation that runs the packager when someone submits source. Today that is one operator command on the build machine.

The honest hydragon loop, until we automate it:

p4 submit source -> operator syncs on the build machine -> hydraunrealengine package
-> submit the package under //hydragon/main/Builds/ -> watcher publishes -> library -> body

That is a real loop. It works today. Automating the middle step is a later improvement, not a prerequisite.

Build machine 2026-09-01: fluffy-dumpling-87 is the only machine that can build today

fluffy was measured and it is a complete Unreal build machine. chunky is not.

fluffy-dumpling-87 chunky-turnip-23
Free disk 1013.8 GB on a 1862 GB C: 113.6 GB total
RAM 31.7 GB 15.7 GB, one module
CPU Ryzen 7 9700X, 8 cores i7-12700K, 12 cores
GPU RTX 5070 Ti RTX A5000 24 GB
Unreal Engine 5.7 installed 5.4.4
Visual Studio 2022 yes no
Windows SDK yes no
Perforce client yes, P4/NTX64/2025.2 none
WDAC user mode off off

fluffy needs one thing it does not have: the hydraunrealengine binary, which is a single download from the release server.

UPDATE 2026-09-01: fluffy is a TEST machine, not in production yet (user). So the production objection below is dropped for now. Build on it. Keep the note because fluffy sits in district bxl1 at venue gallo-romeins-museum and already carries three experiences, so it will not stay free forever. Revisit before the venue goes live.

The original concern, kept for the record: fluffy is a venue body. District bxl1, venue gallo-romeins-museum. It carries the live Gallo-Romeins experience plus mercator-talks and rupelmonde-castle-viewer. Building on it breaks our own rule about never working on production bodies.

What that risk actually looks like: a cook pegs eight cores and the GPU for tens of minutes and writes tens of gigabytes. If a visitor session starts during a cook, the venue experience stutters or fails to launch.

Mitigating facts measured on 2026-09-01: the GPU is idle at 0 percent with 638 MiB of 16303 MiB used, no experience process is running, and the HydraBody scheduled task is Disabled, so hydrabody is not currently managing experiences on this machine. Uptime is 5 days.

Two warnings to carry: fluffy reports three video controllers, two of them Virtual Display Driver entries, which is the #428 double-VDD condition. And no Pico runtime was found under C:\Program Files*, so the belief that fluffy runs Pico Business Streaming co-located needs re-checking before #626 depends on it.

Recommendation. Build on fluffy now, off-hours, with an agreed window and a check that no session is live. It unblocks Phase 1 and Phase 2 immediately at zero cost. In parallel, buy a dedicated build machine so the system seller does not depend on a venue body. Do not wait for the purchase to start.

Perforce machine 2026-09-01: hydragon gets its own. Decided.

User decision: hydragon does not go on hydraskin-perforce-1. It gets a separate Perforce machine. This retires the pool over-commitment risk (#633) for this project, and it stops us putting a game depot next to two live customer scales.

Sizing, from current Hetzner pricing in the hydraexperiencenet context:

Option Spec Price
cx43 plus a Volume 8 cores, 16 GB, 160 GB local, plus a 500 GB Volume about 40 EUR per month
cpx52 12 cores, 24 GB, 480 GB local 100.49 EUR per month
cpx62 16 cores, 32 GB, 640 GB local 129.99 EUR per month

Take the cx43 plus a Volume. It is the cheapest by a wide margin, it matches what hydraskin-perforce-1 already is, and a Volume can grow later without rebuilding the server. Local disk cannot. For a Perforce server, storage matters and cores do not.

Put the depot on the Volume, not on the local disk. That is the whole point.

Perforce on fluffy? No for the server, yes for a proxy. 2026-09-01

Asked: can the Perforce machine be fluffy, rather than a separate box?

The thing you actually want from this is sync speed, and there is a proper answer for it that is not "put the server on fluffy".

The real cost of a remote Perforce server is that the build machine syncs a large Unreal project across the internet, over and over. Perforce solved this a long time ago with P4P, the Perforce Proxy. It caches file content on the local machine. The first sync pulls over the wire; every sync after that is local disk speed. The build machine sees a normal Perforce server.

So: the authoritative p4d runs on the cx43 with the Volume, and a proxy runs on fluffy. The build machine gets local-speed syncs and the source of truth stays somewhere durable.

Why not the server itself on fluffy:

  • All our Perforce tooling is Linux and Incus. hydraperforceprovision, ensure-server, the scale model, the watcher. Running p4d on Windows throws all of it away and makes hydragon a one-off that nobody else can operate.
  • Durability. A Hetzner box has snapshots and images. A venue workstation has neither, unless we build backup for it. This is the source of truth for the product we are betting on.
  • Availability. fluffy sits behind a venue network. We have already lost a node for three days to a dead ethernet port (#613). A source server that is unreachable stops everyone, not just the build.
  • Single point of failure. Build machine and source of truth on one box means one failure loses both, including the history.
  • fluffy will not always be a test machine. It is in district bxl1, venue gallo-romeins-museum, and it already carries three experiences. Today it is free. The plan should not assume it stays free.

The saving is about 40 EUR a month. That is not the right thing to optimise for the depot that holds the game.

Recommendation: authoritative p4d on the cx43 plus Volume, P4P proxy on fluffy. If we want to defer the 40 EUR, the honest version of that choice is "we are accepting no backups and venue-network availability for our source of truth", and it should be a deliberate decision with a date to fix it.

DIRECTION 2026-09-01. The goal is a place to develop, not a demo.

A reconnaissance pass argued for the fastest route to somebody seeing a picture, and it wanted to defer Perforce. That is the wrong optimisation for this project. hydragon is a system seller we will build for months. The foundation matters more than an early screenshot. Corrected priorities, in order:

  1. The build pipeline and Perforce come first. We need a place to check in and build, so real work can start.
  2. The project is a C++ project. Not Blueprint only.
  3. At least one Paragon Serath asset lives in the project from the start, so we can build the environment and evaluate it against real content rather than primitives.
  4. Running with no headset connected is a supported mode, not an accident. You must be able to launch the build flat, look at the environment and judge it, without putting anything on your head.

Render correctness is now #637, split out of this issue. Do not let it block the pipeline work.

Why C++ and not Blueprint only

The first cook on 2026-09-01 used a copy of the engine's TP_VirtualRealityBP template, which is Blueprint only. That was fine to prove a cook runs. It is the wrong base to build on:

  • A Blueprint-only project that enables a code plugin gets treated as code-based anyway, and then the cook demands a built editor target that does not exist. That is #636, and it cost the first two package attempts.
  • A real C++ project has a Source/ directory and builds its own targets, so the problem disappears rather than being worked around.
  • Gameplay systems we already know we need, the teleport node graph, the 10 second cooldown as a tunable data asset, gesture recognition from hand joints, all want C++ underneath, with Blueprint on top.

fluffy already has Visual Studio 2022, the MSVC toolset and the Windows SDK, so the toolchain is not a blocker.

Flat mode, stated properly

The build must run in two modes from one binary:

  • Headset mode. OpenXR, stereo, hand tracking.
  • Flat mode. No headset connected, or -nohmd. A normal window, a camera you can drive with mouse and keyboard, and the same level. Good enough to walk the environment and judge lighting, scale and layout.

This is not only for testing. It is how anyone without a headset reviews the work, and it is how we look at the environment while building it.

Requirements: the flat path must not need a headset to be present or an OpenXR runtime to be running, it must not silently fall back into a broken half state, and it must be obvious which mode you are in.

What the first real project must contain

  • A C++ project, hydragon, in the depot.
  • The OpenXR plugins enabled, as the VR template already does.
  • One lit level you can stand in and look around.
  • At least one Paragon Serath asset placed in that level.
  • A flat mode that works with no headset.
  • The 10 second teleport cooldown value already living in a data asset, not a constant, even before the teleport nodes exist.

Known human step, still outstanding

The Paragon assets come from Fab and need an interactive Epic account login on fluffy. The launcher is installed there and logs SignedIn=0. Nobody can do this remotely. It is on the critical path for the asset requirement above.

Why we build it

  • Venue experiences show the plumbing. A game shows the value. We need one title that sells the platform on its own.
  • The delivery path is the Cyborn path. We check in on our own Perforce, the watcher makes a build, the build lands in the experience library, a body runs it, a head streams it. We become our own creator, so we test the creator pipeline every day.
  • It gives us a VR reference title that we own end to end. No partner, no contract, no waiting.

In scope for the MVP

  1. One map. No three-lane MOBA layout. One lane, built as a chain of teleport nodes.
  2. One playable hero: Serath, in first person VR, driven by hand tracking. No controllers. Node teleport on a 10 second cooldown, hand aim, primary attack, one ability, health, death, respawn.
  3. All other heroes are NPC bots on behaviour trees. One human plus N bots against M bots.
  4. Minions and one tower for each side. This is the smallest set that reads as a MOBA.
  5. Win condition: destroy the enemy core. Target match length 8 minutes.
  6. The game runs on the body and streams in 6DoF to the headset. It is not a standalone headset build.

First person, hand tracking, no controllers. Decided.

You play as Serath in first person. You use your hands. There are no controllers. This is settled. Do not re-open it.

Why no controllers. This is a venue product. Controllers must be handed out, charged, paired, cleaned and replaced. A visitor puts on a headset and plays. Nothing else. That is the operational win, and it is the reason the decision holds even when it makes the build harder.

What it changes:

  • Aim and abilities are gestures. You aim with your hand, not a stick. Abilities fire on pinch, open palm, grab or push. There are no buttons, so the gesture set is the control scheme. Design it in Phase 0 and keep it to four gestures or fewer. Every gesture must be readable, repeatable, and hard to fire by accident.

  • Locomotion is teleport between fixed nodes on the lane. Decided. The map carries a set of marked points along the lane. You aim at one and shoot it, and your centre moves there. The reference is Elven Assassin, where you shoot a tower to stand on it. Inside a node you still lean, turn and step in your own play space. You never slide.

    This is the right answer for three reasons:

    • It reuses the combat aim gesture. Moving and shooting are the same action, so the gesture set stays at four or fewer, and the player learns one thing instead of two.
    • It removes motion sickness. A snap teleport has no smooth movement, so there is nothing to make people sick.
    • It makes position a tactical choice. You pick a node, you commit, you can be punished for it. That is closer to a MOBA than free walking is.

    What it puts on the level designer: the node layout IS the map design. Node count, spacing, sightlines between nodes, and cover at each node decide how the match plays. Nodes must be readable at range, highlight when aimed at, and confirm on hit.

    The teleport has a 10 second cooldown. When you shoot a node, you cannot shoot another one for 10 seconds. You still move freely in your play space. You just cannot change node.

    This is the tactical layer. It turns a movement toy into a decision. You commit to a position and you live with it. Pushing forward is a real risk, because the way back is closed for 10 seconds. Combat becomes about the space you can reach from where you stand, and about reading the enemy's cooldown as well as your own.

    Engineering notes:

    • 10 seconds is a starting number, not a truth. Make it a tunable value in a data asset, never a constant in code. Expect to change it in playtests.
    • The cooldown must be legible without a screen HUD. Show it in the world (nodes stay dark until they can be shot again) and on the hand. Phase 0 picks the form.
    • Sub-decisions for Phase 0: does respawn reset the cooldown, and does the one ability let you break out of a node early? If the ability is an escape, it partly defeats the cooldown, so pick the ability with this in mind.
  • No haptics. All feedback is visual and audio. Hits, casts and damage must read without touch.

  • Tracking loss is a gameplay event. Hands leave the camera view, or one hand hides the other. In a fight, arms move fast. The game must survive lost hands gracefully: no dropped ability, no stuck state, a clear on-screen cue.

  • The Serath asset. Epic shipped Serath as a third person character. In first person with hand tracking you see your own tracked hands, not a rigged controller model. Plan a first person pass: hand meshes driven by joint data, ability VFX that read at arm length, and a camera anchored in the head. Keep the full body for the shadow and for spectators.

  • The bots stay third person. They are seen from outside, so the Paragon assets work as they ship. Only Serath needs the first person pass.

Open technical question, and the one real unknown left. Hand tracking is on the headset. The game is on the body. So the joint data must travel upstream over the XR stream, at a high rate, with low latency.

  • hydraheadquest already uses hand tracking locally in the flat XR client (joint-dot hands, XR_FB_hand_tracking_aim for the hand menu). That proves the headset side, not the stream side.
  • ALVR maps hands to emulated controller poses. Whether full skeletal joint data reaches an Unreal app through SteamVR at usable fidelity and latency must be measured, not assumed. If it only carries emulated controller poses, the gesture set must be built on what does arrive, or the ALVR client fork (#560) must carry the joints.
  • The Pico Business Streaming lane is native OpenXR, so it may pass hands more cleanly. Measure both lanes.

Phase 0 measures this. If the Quest lane cannot carry hands well, that is a finding for #560 and #557, not a reason to add controllers.

Out of scope

Network multiplayer. Hero select. Progression, shop, items. More than one map. More than one playable hero. Matchmaking. Voice chat. Any venue install.

Assets and licence

Epic released the Paragon characters and environments free for use in Unreal Engine projects. Serath is one of them. We use those assets for the MVP.

  • Put the Epic licence terms in the repo, in docs/.
  • The product name is hydragon. We use no Epic marks in the name, the depot, or the build.

Architecture

Source of truth is Perforce. Depot hydragon, mainline //hydragon/main, on the hydraskin p4 scale model, same as galloromeinsmuseum and mercatormetahuman. Provision it with hydraperforceprovision ensure-server.

Build path, unchanged from the Cyborn path:

p4 submit -> hydraperforcewatcher -> hydramirror -> hydracluster notify -> hydraexperiencelibrary -> body

Run path: hydrabody starts the build on the body in its XR provider role. The head receives the stream.

The XR stream path already exists. We consume it.

hydragon does NOT need to invent VR streaming. The 6DoF chain is built and proven under #544.

Proven on 2026-08-26: gallo-romeins-museum streamed in true 6DoF from body chunky-turnip-23 (SteamVR plus ALVR 20.14.1) to a Quest 2 over the mesh, off venue, user confirmed. The full chain shipped the same day: hydracluster stream_mode: xr, hydrabody with an alvr role and advertised xr_drivers, hydraexperiencelibrary stream_mode field, hydraheadquest v0.8.0 with the XR handoff.

The policy is settled (#544):

  • Quest bodies: ALVR plus SteamVR. Our own builds through SteamVR on one dedicated account for each body.
  • Pico bodies: Pico Business Streaming 2.x. Native OpenXR, no SteamVR, no accounts. This is the golden path for enterprise. Body fluffy already runs the PBS runtime.
  • Linux bodies: WiVRn, later (#561, fits #508).
  • CloudXR is rejected. It is a proprietary runtime layer and NVIDIA only.

So hydragon publishes as stream_mode: xr and rides the existing chain. The work is engine-side and content-side, not transport-side.

One advantage we have over Gallo. The Gallo XR test showed a black HMD view, because the Unreal app did not render to the headset. We own the hydragon source, so we control OpenXR and SteamVR startup directly. hydragon can become the reference title that proves the chain, and a clean test signal for #556 to #560.

Open XR items we inherit, not solve here: #556 cluster stream_mode model and exclusive slots, #557 hydrabody tri-mode roles and vrserver supervision, #558 Quest XR handoff, #559 hydraheadpico with PBS, #560 the Hydra ALVR client fork, #561 WiVRn spike. If any of these block a hydragon phase, file the blocker on that issue, not here.

SUPERSEDED: chunky-turnip-23 as the build machine

chunky was chosen on 2026-08-31 on the assumption it had room. The measurement showed 113.6 GB free against a 500 GB need, 15.7 GB of RAM, a mechanical D: drive, Unreal 5.4.4, and no Perforce client or C++ toolchain.

The build machine is fluffy-dumpling-87. See the 2026-09-01 section above. chunky stays what it always was: the reference XR test body.

Ordered plan

Phase 0. Decide.

  • Pick the Unreal Engine version and pin it. UE 5.7 is already in use on fluffy for hydramark (#513).
  • Confirm the build machine. chunky-turnip-23 is decided (see above). Measure free disk before the first Perforce sync, and agree the build-versus-test window. quest-head-36afcd is the reference XR head.
  • Run the hand tracking spike first. Measure whether hand joint data reaches an Unreal app on the body, on the Quest lane (ALVR plus SteamVR) and on the Pico lane (PBS). Record fidelity, rate and added latency. Everything else in the design depends on the answer.
  • Design the gesture set. Four gestures or fewer. Aim and shoot covers both attack and node teleport, so the set needs: aim and shoot, one ability, and one menu gesture. Decide how the game tells an attack shot from a teleport shot: the target decides it, not the gesture. Write it down before anyone builds it.
  • Design the node layout. Locomotion is already decided (shoot a node to teleport to it, then wait 10 seconds). Set the node count, the spacing, the sightlines between nodes, and the cover at each node. Spacing and cooldown work together: a node you cannot leave for 10 seconds needs enough to fight from. This is the map design.
  • Pick how the cooldown reads to the player, in the world and on the hand. Decide whether respawn resets it and whether the ability can break it.
  • Decide whether the bots use the node graph or walk freely. Free walking bots against a node-hopping player is a different game from both sides hopping. Pick one and write down why.
  • Set the frame budget. VR wants 72 to 90 frames for each eye, and the encoder wants headroom.

Phase 1. Perforce.

  • Provision the hydragon scale and depot with ensure-server, on port 1668. Do NOT set 200 GiB: the shared pool is 106 GiB and over-committing it wedges Cyborn's live scale. Add storage or use a separate node first, then size it honestly.
  • Create the users and the group. Least privilege on //hydragon/....
  • Add the depot to hydraperforcewatcher. Add .hydrabuild.yaml.
  • Write the runbook and the testbook.
  • Done when a trivial submit makes a build that shows up in the experience library, with no manual copy.

Phase 2. Vertical slice.

  • Empty map, Serath pawn, VR pawn, hand tracked aim, one attack, one target dummy, and two teleport nodes with a working hop and the 10 second cooldown between them.
  • Make it render to the HMD correctly from the first commit. This is the Gallo lesson.
  • Package it. Submit it. Register it with stream_mode: xr. Run it on chunky. Stream it to the Quest.
  • Done when a person shoots the dummy in VR, in 6DoF, with their bare hands, over the stream.

Phase 3. The game.

  • Bots for the other heroes. Minions. One tower for each side. The core.
  • Health, death, respawn, win condition, match timer.
  • Done when a full match runs to a win.

Phase 4. Both XR lanes.

  • Verify hydragon on the Quest lane (ALVR plus SteamVR) and the Pico lane (PBS on fluffy).
  • Feed the results back to #557 and #559. hydragon is the test title for both.
  • Done when the same build runs on both lanes with no per-lane content change.

Phase 5. Show it.

  • Run it at bxl1-test on a test body. Never on a production body.
  • Measure frame rate, latency and comfort over a full match.

Definition of done

One person puts on a headset. The match starts. They play Serath for about 8 minutes against bots. They destroy the enemy core. They never touch a controller, and they never slide. The whole match streams in 6DoF from a Hydra body to the headset, and the build on that body came from a Perforce submit with no manual copy.

Risks

  1. Getting chunky able to build at all. This is now the top risk, and it is a human decision about deleting data, not an engineering problem. 113.6 GB free against a 500 GB need. Nothing starts until it is settled.
  2. Storage on the Perforce node. A 200 GiB quota on a 106 GiB shared pool is a lie that ends with Cyborn's live scale wedged. Add storage or give hydragon its own node before provisioning.
  3. Nobody packages Unreal for us. The watcher publishes what we submit. Automated cooking does not exist and is unscoped. Somebody submits a packaged build by hand until we build that.
  4. Hand tracking over the stream, mostly retired. ALVR 20.14.1 already sends the full 31 bone skeleton to SteamVR. Only the SteamVR to OpenXR binding stays unproven, and one small probe settles it. Findings still go to #560 and #557.
  5. Gesture design. With no buttons, the gesture set IS the game. Bad gestures fire by accident or fail to fire in a fight. Budget real design time, and test with people who have never worn a headset.
  6. Tracking loss in combat. Arms move fast and hands hide each other. The game must handle lost hands without a stuck state or a dropped ability.
  7. Node layout and cooldown tuning. Teleport nodes solve the sickness problem, so the risk moves to design. Too few nodes and the lane feels static. Too many and the player teleports instead of fighting. A cooldown that is too long feels like a punishment; too short and the commitment disappears. Nodes that read badly at range make the player feel stuck. Keep both the layout and the 10 seconds tunable, and test over a full 8 minute match, not for 2 minutes.
  8. Frame budget. Two eyes at 72 to 90 frames, plus the encoder, on a machine with 16 GB of RAM. Plan a cut-down pass on the map.
  9. XR chain stability. The transport works, but #557 notes that vrserver does not survive overnight and needs supervision. A long demo needs that fixed. Track it on #557.
  10. Scope creep towards a real MOBA. The out of scope list above is the guard. Change it only in this issue.
  11. hydramirror capacity. 2.52 GB free of 40 GB. A real Unreal package will not upload. Free space before Phase 2.

Related

  • #544 hydraheadquest. The XR head and the settled Phase 3 policy.
  • #556, #557, #558, #559, #560, #561. The XR chain issue set. hydragon consumes all of it.
  • #513 hydramark. Our own Unreal project, build and package pattern.
  • #508 Linux body pipeline. The WiVRn lane.
  • #504 multi-stream bodies. Slot model. #556 makes XR slots exclusive.
  • #479, #541. The Perforce onboarding pattern we copy.
  • #543. ensure-server hardening.

Sub-issues

Filed 2026-08-31, one for each phase, all parented to this issue:

  • #622 Phase 0. Decide engine, build machine, gestures, node layout. Spike hand tracking over the stream. Everything waits on this.
  • #623 Phase 1. Perforce depot hydragon, watcher, first build in the experience library.
  • #624 Phase 2. Vertical slice: Serath, hand aim, two nodes with the cooldown, streamed in 6DoF.
  • #625 Phase 3. The game: bots, minions, tower, core, win condition.
  • #626 Phase 4. Verify both XR lanes.
  • #627 Phase 5. Full 8 minute match at bxl1-test, measured.
  • #634. Automate the build: a submit to //hydragon/main produces a build with no human step. Filed 2026-09-01.

Sub-issues (9)

open #741 Validate Hydra Unreal Template / Hydragon baseline with the WiVRn build on MSI1060
open #637 hydragon OpenXR build renders only partial scene flat: Depth Stencil Format 0x0 in the RHI log
open #634 hydragon: automate the build so a submit to //hydragon/main produces a build with no human step
open #627 hydragon Phase 5: full 8 minute match at bxl1-test, measured
open #626 hydragon Phase 4: verify both XR lanes - ALVR/SteamVR on Quest, Pico Business Streaming on Pico
open #625 hydragon Phase 3: the game - bots, minions, tower, core, win condition
open #624 hydragon Phase 2: vertical slice - Serath, hand aim, two nodes with cooldown, streamed in 6DoF
open #623 hydragon Phase 1: Perforce depot hydragon, watcher, first build in the experience library
open #622 hydragon Phase 0: decide engine, build machine, gestures, node layout; spike hand tracking over the stream