This file provides guidance to Codex (Codex.ai/code) when working with code in this repository.
FRIK (Fallout 4 VR Body) is a Fallout 4 VR mod that adds full-body IK, weapon repositioning, an in-VR Pipboy, and hand-pose / finger control. It builds as an F4SE plugin DLL (FRIK.dll).
The project is built on top of F4VR-CommonFramework, which is included as a git submodule and provides the plugin lifecycle (ModBase), config base (ConfigBase), VR controller framework (vrcf), VR UI widgets (vrui), and game/skeleton helpers (f4vr, f4sevr). Reading the framework's AGENTS.md is the fastest way to understand the namespaces (f4cf::, f4cf::f4vr, f4cf::vrcf, f4cf::vrui, f4cf::common) and the ModBase lifecycle hooks.
Prerequisites:
VCPKG_ROOTenvironment variable must point to a vcpkg installation- Visual Studio 2022 (v143) or 2026 (v145), x64
- CMake 4.2+
- Init submodules:
git submodule update --init --recursive
Generate solution:
cmake --preset default # uses vs2026 by default
For local development, copy CMakeUserPresets.json.template → CMakeUserPresets.json and set:
POST_BUILD_COPY_PLUGIN: trueandCOPY_PLUGIN_BASE_PATHto your MO2 mod folder(s) (semicolon-separated for multiple) — this auto-copiesFRIK.dll+.pdbto<path>/F4SE/Plugins/after every build.F4VR_COMMON_FRAMEWORK_PATHto point to a sibling checkout of F4VR-CommonFramework if you want to develop against it instead of the submodule.
Build (and ALWAYS check the output before reporting done):
cmake --build build 2>&1 | tee build_output.txt
Then read build_output.txt. Release builds also produce a versioned .7z package in build/package/.
src/FRIK.cpp defines F4SEPlugin_Query/F4SEPlugin_Load, which delegate to f4cf::g_mod. The mod itself is the frik::FRIK class in src/FRIK.h, instantiated as the global singleton frik::g_frik. It extends f4cf::ModBase and overrides:
onModLoaded— installs game hooks viafrik::hook::patchAll()/hookMain()(src/GameHooks.h)onGameLoaded— registers Papyrus natives, detects Fallout London VR / BetterScopesVR, adds embedded flashlight keywordonGameSessionLoaded— fires on new game and every save load; releases skeleton and reconfigures game INI varsonFrameUpdate— drives the per-frame update of every subsystem
FRIK owns the lifetimes of Skeleton, Pipboy, ConfigurationMode, and WeaponPositionAdjuster. They are created lazily in initSkeleton() once the game's player + camera + bone-tree nodes are all available (isGameReadyForSkeletonInitialization), and destroyed/recreated on power-armor change, root-node release, or loading-screen transitions (releaseSkeleton).
FRIK::onFrameUpdate() runs in this order — order matters because later subsystems read state set by earlier ones:
- Validate root node and power-armor state (rebuild skeleton if either changed)
Skeleton::onFrameUpdate— IK, body posture, walking, hand pose (src/skeleton/Skeleton.cpp)BoneSpheresHandler::onFrameUpdate— interaction-sphere collision/eventsPlayerControlsHandler::onFrameUpdate— enable/disable player movement based on UI stateWeaponPositionAdjuster::onFrameUpdate— weapon offsets, offhand grip, reposition modePipboy::onFrameUpdate— wrist Pipboy logic, finger interaction, flashlightvrui::g_uiManager->onFrameUpdate— VR UI widgets (driven byFrameUpdateContextadapter that exposes the offhand index-finger tip and hand-pointing pose)MainConfigMode+ConfigurationMode— config UI renderingupdateWorldFinal— three engine-level scene-graph updates (BSFadeNode_MergeWorldBounds,BSFlattenedBoneTree_UpdateBoneArray,BSFadeNode_UpdateGeomArray) needed for cull geometry, finger position, and Pipboy interaction to work correctly
FRIK::smoothMovement is invoked from a separate hook (not from onFrameUpdate).
| Subsystem | Location | Responsibility |
|---|---|---|
| Skeleton/IK | src/skeleton/ | Body IK, leg walking, head/neck posture, arm solver, fingers via HandPose |
| Hand pose | src/skeleton/HandPose.cpp, HandPoseData.cpp | Tagged hand-pose override stack with priority; supports Dynamic, Override, and PrimaryWeaponPose sources |
| Pipboy | src/pipboy/ | Wrist & holo Pipboy, physical (finger-touch) interaction, flashlight |
| Weapon positioning | src/weapon-position/ | Per-weapon offsets, offhand-grip two-handed mode, in-game reposition tool |
| Smooth movement | src/smooth-movement/ | Reduce VR motion sickness on locomotion |
| Config UI | src/config-mode/ | In-VR config menus (MainConfigMode, ConfigurationMode, BodyAdjustmentSubConfigMode) |
| Reload | src/reload/ | Two-handed gun reload interaction |
| Public API | src/api/FRIKApi.h | C ABI exposed to other mods (loaded via GetProcAddress on FRIKAPI_GetApi) |
| Papyrus API | src/PapyrusApi.h | Native functions for in-game scripts |
src/Config.h / src/Config.cpp extends f4cf::ConfigBase. Files live under %USERPROFILE%\Documents\My Games\Fallout4VR\FRIK_Config\:
FRIK.ini— main settings (also embedded as RCDATAIDR_FRIK_INI, extracted on first run)FRIK_FOLVR.ini— Fallout London VR overrides, merged on top when that mod is detectedMesh_Hide/face.ini,skins.ini,slots.ini— geometry hide listsPipboy_Offsets/*.json— per-Pipboy-style world offsetsWeapons_Offsets/*.json— per-weapon offsets, by mode (WeaponOffsetsMode: Weapon / PrimaryHand / OffHand / Throwable / BackOfHandUI) with_PAand_leftsuffix variants
g_config.fEqual() and friends — see "Conventions" below for float comparisons. The base class auto-reloads on file change via the file watcher.
frik::api::FRIKApi (src/api/FRIKApi.h) is a struct of C function pointers exposed via the exported FRIKAPI_GetApi (src/exports.def). Other mods copy the header into their project, call FRIKApi::initialize(), and use inst->setHandPose(...), inst->getIndexFingerTipPosition(...), inst->blockOffHandWeaponGripping(...), etc. Bump FRIK_API_VERSION whenever you change the struct layout — clients version-check against it. Hand poses use a string tag so multiple systems can layer overrides without clobbering each other.
For mods that want a button in FRIK's main config menu: they call registerOpenModSettingButtonToMainConfig; FRIK dispatches an F4SE message back to them when the button is clicked. Sender name is F4VRBody (also exposed as BETTER_SCOPES_VR_MOD_NAME/FRIK_F4SE_MOD_NAME).
- BetterScopesVR — registers as a message listener at startup; messages of type 15 update
_isLookingThroughScope, which gates dampening behavior. - Fallout London VR — detected via
isFalloutLondonVRModLoaded(); loadsFRIK_FOLVR.inioverrides and switches Pipboy to "Attaboy" mode. Can be force-disabled withignoreFalloutLondonVR. - Immersive Flashlight VR — if loaded, FRIK skips its embedded flashlight to avoid conflict.
- Build verification: Always build via
cmake --build build 2>&1 | tee build_output.txtand readbuild_output.txtbefore reporting a change as done. Don't skip this step. - Float comparisons: Use
common::fEqual()(fromF4VR-CommonFramework'scommon/CommonUtils.h) instead of==/!= 0.0fagainst floats. - Code style: clang-format enforced (LLVM-based, 180-col, 4-space indent, CRLF, pointer-left, namespace indentation). C++23, MSVC
/W4 /WX(linker),_UNICODE,/permissive-, all common/Zc:conformance flags. - PCH: src/PCH.h is precompiled —
F4SE/F4SE.h,RE/Fallout.h,REL/Relocation.h,Logger.h,Version.h, andusing namespace f4cfare implicit in every TU. - Logging: Use
logger::trace/debug/info/warn/error(spdlog wrappers).logger::sample(ms, ...)rate-limits noisy logs to once perms. - No in-source builds: CMake hard-fails if you try.