feat(runtime): add an opt-in free camera and MODEL VIEWER mode
What
An opt-in free camera and a MODEL VIEWER mode. Everything is behind the new Free camera launcher checkbox (or RECOMP_FREE_CAMERA=1), which is off by default. With it off, the runtime installs none of the hooks and the game is unchanged.
With it on:
- Free camera anywhere. F1 (or a click of the right stick) takes the game's camera: WASD/QE or the left stick and triggers move, arrows, the right stick or a right-mouse drag look, and Z/X zoom. It works in matches, the real-time demo, the island map, the menus, the poolside (including Take a rest and the hopping game), the hotel room and the shops.
- Pause anywhere. P (or Start while flying) freezes the scene while it keeps drawing, so the camera can move around a still frame.
./RB steps a frame. H/LB gives a clean view without the game's overlay or the panel. - Animation and swimsuit, live.
[ ]or the d-pad's left/right browse the loaded animation clips.- =or the d-pad's up/down put any swimsuit she can wear on her, without leaving the scene. - MODEL VIEWER in the main menu. Pick a girl, her swimsuit, a court and the time of day. When the match starts, the viewer takes over: the free camera stands in front of her, the other players, the ball and the score are hidden, and the panel shows her name, animation and swimsuit. Turning the camera off returns to the main menu.
- Screenshots. F12 (or Back + A while flying) saves a PNG of the game's frame.
- Overlay panel. A small Dear ImGui panel lists the controls. It shows controller or keyboard hints after whichever was used last.
Screenshots
Main menu:

Character select (only Player 1's column):

Court select, with the time of day hint:

In the viewer, with the overlay panel:

A 54-second captioned demo video, recorded headless at 720p: . It shows Lei Fang on animations 15 to 20, live swimsuit changes, flying while paused, leaving the viewer, and the free camera on the main menu.
How it works
All of it is runtime code; the generated game C is untouched. The details and the guest addresses are in docs/free-camera.md and docs/model-viewer.md.
- Camera. The game builds its view from one of five camera objects at
0x41A800in0x00023B10. The free camera puts its own eye, target and field of view in place for that build. It flies the object whose view the most draws used in the last frame: the draw adapter reports each draw's view transform. - Freeze. The game runs its systems as cooperative tasks on fibers. The freeze declines the turns of tasks that have not drawn lately, so the drawing tasks keep the picture on screen. Where the camera is built in a task the freeze skips, the free camera builds it itself. It also updates the scene's copies of the view and projection (
0x4D6F20,0x4D95F0) that the drawing task hands the device. - Animation. Clip requests go to the character's animation layer, and her root is held in place.
- Swimsuit. At the camera build, the old suit is released and the new one requested through the game's own loader. Only the loader task runs until the suit is bound, with presentation held, so nothing draws her half-loaded.
- Model viewer. A main-menu item drives the Exhibition menus: One Player, the other players' picks, and a draw mask that shows only Player 1's column. It takes over once the match has settled.
- Overlay. Dear ImGui 1.91.9, fetched by URL and SHA-256, draws onto the swapchain after the game's frame: SDL_GPU on macOS and Linux, D3D11 on Windows.
Verification
- Played by the author on macOS (Metal) throughout development, including the poolside, hotel room and shops cases and keyboard and controller flight, and on a Steam Deck (SteamOS, Vulkan).
- Headless scripted runs on macOS for each feature: the camera drift, freeze and step, clip and suit changes (in a CPU match, the frozen viewer and the demo), the viewer's menus, the hidden ball and others, the hotel room's camera choice, and a run with the checkbox off that shows the stock main menu.
ctest: all 36 tests pass (custom-music skipped), in a public-only configure of the pushed commit.tools/public_export.py verify --require-public-treepasses.
Not tested: the Windows D3D11 overlay was cross-built with llvm-mingw but never run, and the tools Python tests were not run locally (my Python is too old for them). Frame stepping backwards is not implemented.
The author's own demo video will follow in a comment.