This update supersedes stale infrastructure/build assumptions below; earlier project decisions remain history.
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.
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.
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.
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.
chunky-turnip-23 was measured. It is an HP Z2 (hostname Sanctuary-AD6):
SignedIn=0. Paragon assets need an interactive login.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.
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.
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.
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.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.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.hydragon repo or depot exists anywhere yet.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.
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.
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.--deliver zips the result and uploads it to HydraTransfer.serve), and self-update from the release server.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.
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.
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.
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:
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.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.
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:
Render correctness is now #637, split out of this issue. Do not let it block the pipeline work.
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:
Source/ directory and builds its own targets, so the problem disappears rather than being worked around.fluffy already has Visual Studio 2022, the MSVC toolset and the Windows SDK, so the toolchain is not a blocker.
The build must run in two modes from one binary:
-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.
hydragon, in the depot.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.
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:
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:
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.
XR_FB_hand_tracking_aim for the hand menu). That proves the headset side, not the stream side.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.
Network multiplayer. Hero select. Progression, shop, items. More than one map. More than one playable hero. Matchmaking. Voice chat. Any venue install.
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.
docs/.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.
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):
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.
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.
Phase 0. Decide.
Phase 1. Perforce.
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.//hydragon/.....hydrabuild.yaml.Phase 2. Vertical slice.
stream_mode: xr. Run it on chunky. Stream it to the Quest.Phase 3. The game.
Phase 4. Both XR lanes.
Phase 5. Show it.
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.
Filed 2026-08-31, one for each phase, all parented to this issue: