Hello everyone,
I have created an open-source patch that unlocks the frame rate of the Touhou games (a famous series of 2D shmups, hard-locked to 60 FPS) so they can be presented and played at 144, 240 or 360 Hz without changing the speed of the game itself.
The simulation is not simply run faster. The game's logic keeps its exact 60 Hz schedule, and motion is integrated in sub-steps whose
durations add up to exactly one frame -- so anything left undisturbed, e.g. a bullet on a straight line or the player holding a direction, is exactly where the unmodified game would have put it at every 60 Hz boundary.
What changes is the decisions made in between: input is polled and the player moved once per drawn frame, and collision is tested at every sub-step instead of once. A bullet that would have jumped clean past you between two 60 Hz frames can now hit you. So it is genuinely higher-rate gameplay and input rather than interpolated presentation.
Slow-motion camera comparison on a 360 Hz OLED, 60 Hz vs patched:
Feature showcase (it also adds optional accessibility/upscaling features):
This was reverse-engineered and written almost entirely with AI assistance. I used ChatGPT Astra for the early work, and Claude Fable/Opus for most of the rest, on top of Ghidra. I directed it, made the design decisions and verified the results, but I would not have been able to do this alone despite my software engineering background. It is a few thousand lines of x86 and AMD64 patching across five game builds, and finding the sites by hand would have taken months I do not have.
I think that is extremely cool. There are a lot of old games locked to 30 or 60 FPS where the fix is "someone has to reverse-engineer the frame loop and figure out which systems can be sub-stepped safely". That used to need a specialist with a lot of free
time. It is now tractable for anyone willing to learn enough to check the AI's work. Checking is still mandatory, because it confidently got things wrong several times, and only tests and instrumentation caught it. If you have a 60 Hz-locked game you love, I would genuinely encourage you to try!
Everything is MIT-licensed and the full reverse-engineering notes are in the repository, including the schedule arithmetic and the parts I got wrong on the way:
https://github.com/vittorioromeo/th12_hfr
Enjoy!
I used AI to turn a 60 FPS-locked game into true high-refresh title
-
vittorioromeo
- Posts: 1
- Joined: 13 Sep 2026, 19:23
-
yulorien
- Posts: 3
- Joined: Yesterday, 05:37
Re: I used AI to turn a 60 FPS-locked game into true high-refresh title
If I'm reading the scheme right, the sub-steps per logic frame are only a whole number when the refresh rate is an exact multiple of 60 — and of the three you list, 144 isn't one.
240Hz gives a constant 4 sub-steps per 60Hz logic frame, 360Hz a constant 6. At 144Hz the ratio is 2.4, so it can't be constant: walking the boundaries (logic at k/60, drawn at j/144) it repeats every 5 logic frames / 12 drawn frames, with counts 3,2,3,2,2 — phase depending on which side of the boundary you count.
So collision granularity oscillates on a 144Hz panel: some logic frames get tested three times, some twice. Since the point of sub-stepping here is closing the tunnelling window, what bounds your hit detection is the worst-case 2-sub-step frame, not the 2.4 average. And because it's periodic and deterministic rather than jitter, it should be reproducible — which at least makes it straightforward to instrument if you want to check whether it's visible in practice.
165Hz is worse in the same way (11 drawn per 4 logic, 3,3,3,2). Decoupling the sub-step count from drawn frames — fixed N per logic frame, present whenever the panel is ready — makes it uniform, but then input no longer lands exactly on sub-step boundaries, which may well be the worse trade for a shmup. Mostly just worth knowing which of the three refresh rates is the odd one out.
240Hz gives a constant 4 sub-steps per 60Hz logic frame, 360Hz a constant 6. At 144Hz the ratio is 2.4, so it can't be constant: walking the boundaries (logic at k/60, drawn at j/144) it repeats every 5 logic frames / 12 drawn frames, with counts 3,2,3,2,2 — phase depending on which side of the boundary you count.
So collision granularity oscillates on a 144Hz panel: some logic frames get tested three times, some twice. Since the point of sub-stepping here is closing the tunnelling window, what bounds your hit detection is the worst-case 2-sub-step frame, not the 2.4 average. And because it's periodic and deterministic rather than jitter, it should be reproducible — which at least makes it straightforward to instrument if you want to check whether it's visible in practice.
165Hz is worse in the same way (11 drawn per 4 logic, 3,3,3,2). Decoupling the sub-step count from drawn frames — fixed N per logic frame, present whenever the panel is ready — makes it uniform, but then input no longer lands exactly on sub-step boundaries, which may well be the worse trade for a shmup. Mostly just worth knowing which of the three refresh rates is the odd one out.
Last edited by yulorien on 16 Sep 2026, 12:04, edited 1 time in total.
