Skip to content

Commit b646a97

Browse files
committed
Limiter calculator
1 parent 95c9d75 commit b646a97

File tree

5 files changed

+148
-132
lines changed

5 files changed

+148
-132
lines changed

css/styles.css

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -219,7 +219,7 @@ textarea {
219219
}
220220

221221
button.active {
222-
background-color: #4CAF50;
222+
background-color: #e3b2da;
223223
color: white;
224224
}
225225

falloutnv.html

Lines changed: 19 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
<link rel="icon" type="image/x-icon" href="img\favicon.webp">
2929
<script src="js/javascript.js"></script>
3030
<script src="js/perfguide.js"></script>
31+
<script src="js/fpsCalculator.js"></script>
3132

3233
<link rel="manifest" href="manifest.json">
3334
<link rel="stylesheet" href="css/styles.css">
@@ -1164,64 +1165,31 @@ <h4>Installation and configuration</h4>
11641165
</li>
11651166
<li>
11661167
Enter your refresh rate here for automatic calculation of FPS limits. You can find your exact refresh rate <b><a href="https://www.testufo.com/refreshrate" target="_blank">here</a></b>.
1167-
<div>
1168-
<input id="rrRTSS" type="number" step="any" id="refreshRateInput" placeholder="Enter your refresh rate here" min="60" value="60" onchange="refreshRateCalculations(this)" style="width: 80px;">
1169-
<button id="rrSubmit" onclick="refreshRateCalculations(rrRTSS)" style="margin: 5px;">Calculate</button><span class="disabled" id="applyConfirmation">Done!</span> <span class="disabled" id="applyError">Due to physics issues, it's not recommended to go above 120 FPS.</span>
1168+
</li>
1169+
<div class="card-basic">
1170+
<div class="center" style="margin: 10px;">
1171+
<button id="fixedButton" onclick="setMode('fixed')" class="active">Fixed Refresh</button>
1172+
<button id="vrrButton" onclick="setMode('vrr')">VRR</button>
1173+
<input type="hidden" id="refreshMode" value="fixed">
11701174
</div>
1171-
<div class="card-red">
1172-
<p>
1173-
Even with New Vegas Tick Fix, game can still have issues with high framerates. It's recommended to cap your framerate to 120 FPS or below.
1174-
</p>
1175+
1176+
<div class="center" style="margin: 10px;">
1177+
<label for="refreshRate">Monitor refresh rate: </label>
1178+
<input id="refreshRate" type="number" step="1" placeholder="e.g. 60, 144" min="60">
1179+
<button onclick="calculateFPS()">Calculate</button>
11751180
</div>
1176-
</li>
1177-
<li>
1178-
Set <b>Framerate Limit</b> to:
1179-
<ul>
1180-
<li>
1181-
V-Sync
1182-
<div class="card-basic">
1183-
<p>
1184-
<span class="fpsVSync">(RefreshRate - 0.05)</span>
1185-
</p>
1186-
</div>
1187-
</li>
1188-
<li>
1189-
VRR + V-Sync
1190-
<div class="card-basic">
1191-
<p>
1192-
Any value between 48 and <span class="fpsVRR">(RefreshRate * (1 - RefreshRate * 0.00028))</span>.
1193-
</p>
1194-
<div class="card-yellow">
1195-
<p>
1196-
You should select a value that will match your average obtainable framerate in the game.
1197-
</p>
1198-
</div>
1199-
</div>
1200-
</li>
1201-
<li>
1202-
No V-Sync
1203-
<div class="card-basic">
1204-
<p>
1205-
<span class="fpsFixed">(RefreshRate)</span>
1206-
</p>
1207-
</div>
1208-
</li>
1209-
</ul>
1210-
</li>
1181+
1182+
<div id="fpsResults" style="display: none;"></div>
1183+
</div>
1184+
12111185
<li>
12121186
Enter settings using Setup button and:
12131187
<ul>
1214-
<li>
1215-
Enable <b>Passive Waiting</b>
1216-
</li>
1217-
<li>
1218-
Set framerate limiter to <b>Front Edge Sync</b>
1219-
</li>
1188+
<li>Enable <b>Passive Waiting</b></li>
1189+
<li>Set framerate limiter to <b>Front Edge Sync</b></li>
12201190
</ul>
12211191
</li>
1222-
<li>
1223-
Enable <b>Start with Windows</b> or launch RTSS everytime before you play
1224-
</li>
1192+
<li>Enable <b>Start with Windows</b> or launch RTSS everytime before you play.</li>
12251193
<p>
12261194
Your configuration should look similar to this:
12271195
<br>

js/fpsCalculator.js

Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
const commonRates = [60, 120, 144];
2+
const MAX_RECOMMENDED_FPS = 120;
3+
4+
function findNearestRateWithGoodDivisor(rate) {
5+
const validRates = commonRates.filter(r => r <= rate);
6+
7+
if (validRates.length === 0) return 60;
8+
9+
// Find the highest valid rate that's not above user's refresh rate
10+
return validRates.reduce((prev, curr) =>
11+
Math.abs(curr - rate) < Math.abs(prev - rate) ? curr : prev
12+
);
13+
}
14+
15+
function setMode(mode) {
16+
const fixedBtn = document.getElementById("fixedButton");
17+
const vrrBtn = document.getElementById("vrrButton");
18+
19+
if (mode === 'vrr') {
20+
vrrBtn.classList.add('active');
21+
fixedBtn.classList.remove('active');
22+
} else {
23+
fixedBtn.classList.add('active');
24+
vrrBtn.classList.remove('active');
25+
}
26+
27+
document.getElementById("refreshMode").value = mode;
28+
document.getElementById("fpsResults").style.display = "none";
29+
}
30+
31+
function getLargestDivisors(number) {
32+
const divisors = [];
33+
for (let i = 1; i <= number; i++) {
34+
if (number % i === 0) {
35+
divisors.push(i);
36+
}
37+
}
38+
return divisors;
39+
}
40+
41+
function hasSuboptimalDivisors(number) {
42+
// Check for decimal division results between 30-60Hz
43+
for (let i = 2; i <= 5; i++) {
44+
const divisor = number / i;
45+
if (divisor >= 30 && divisor < 60) {
46+
return true;
47+
}
48+
}
49+
// Also check whole number divisors
50+
return getLargestDivisors(number).some(d => d >= 30 && d < 60);
51+
}
52+
53+
function calculateFPS() {
54+
const rr = parseFloat(document.getElementById("refreshRate").value);
55+
const mode = document.getElementById("refreshMode").value;
56+
const results = document.getElementById("fpsResults");
57+
58+
if (!rr || rr < 60) {
59+
results.innerHTML = `
60+
<div class="card card-red">
61+
<p>Enter a valid refresh rate of 60Hz or higher.</p>
62+
</div>
63+
`;
64+
results.style.display = "block";
65+
return;
66+
}
67+
68+
if (mode === 'vrr') {
69+
const rrVRR = Math.round(rr * (1 - rr * 0.00028));
70+
// clamp VRR upper recommendation to MAX_RECOMMENDED_FPS
71+
const rrVRRClamped = Math.min(rrVRR, MAX_RECOMMENDED_FPS);
72+
results.innerHTML = `
73+
<div class="card card-basic">
74+
<p>Recommended FPS Limit Range: Any value from 48* to ${rrVRRClamped}</p>
75+
</div>
76+
<div class="card card-yellow">
77+
<p>
78+
*Your VRR range typically starts at 48 FPS, but some displays support 30 or even 1.<br>
79+
Check <a href="https://www.nvidia.com/en-us/geforce/products/g-sync-monitors/specs/" target="_blank">this list</a> to know your model's VRR range. Check the product page if it's not listed there.
80+
</p>
81+
</div>
82+
<div class="card card-green">
83+
<p>
84+
Choose the highest value your system can maintain consistently.
85+
</p>
86+
</div>
87+
`;
88+
} else {
89+
// only include divisors within the allowed recommendation range and >=60
90+
const usableDivisors = getLargestDivisors(rr).filter(d => d >= 60 && d <= MAX_RECOMMENDED_FPS);
91+
let recommendations = usableDivisors.map(d =>
92+
d === rr ? `${(d - 0.05).toFixed(2)}` : d
93+
).join(' or ');
94+
95+
let warning = '';
96+
if (!commonRates.includes(rr) && rr > 75) {
97+
const better = findNearestRateWithGoodDivisor(rr);
98+
warning = `
99+
<div class="card card-red">
100+
<p>
101+
Your refresh rate (${rr}Hz) has divisors that make it suited for VRR more than fixed refresh.<br>
102+
Look into enabling VRR if your display supports it. If not, consider switching to <b>${better}Hz</b> instead if you can't hold performance close to the suggested value - you can do this in the <b>Nvidia Control Panel</b> or <b>Adrenalin</b> settings.
103+
</p>
104+
</div>
105+
`;
106+
}
107+
108+
results.innerHTML = `
109+
<div class="card card-basic">
110+
<p>Recommended FPS ${usableDivisors.length === 1 ? 'Limit' : 'Limits'}: ${recommendations} (choose one)</p>
111+
</div>
112+
${warning}
113+
<div class="card card-green">
114+
<p>
115+
Choose the highest value your system can maintain consistently.
116+
</p>
117+
</div>
118+
<div class="card card-red">
119+
<p>
120+
Even with New Vegas Tick Fix, the game can still have issues at high framerates, the calculator already accounts for this and won't return any value higher than 120.
121+
</p>
122+
</div>
123+
`;
124+
}
125+
126+
results.style.display = "block";
127+
}

js/perfguide.js

Lines changed: 0 additions & 79 deletions
Original file line numberDiff line numberDiff line change
@@ -35,85 +35,6 @@ function createImageHandlers() {
3535
});
3636
}
3737

38-
function largestCommonFactor(rate) {
39-
for (let i = 120; i > 0; i--) {
40-
if (rate % i === 0) {
41-
return i;
42-
}
43-
}
44-
return 1;
45-
}
46-
47-
function handleRRConfirmation(rr) {
48-
if (rr > 120) {
49-
const errorMsg = document.getElementsByClassName("applyError");
50-
}
51-
else if (rr >= 60) {
52-
const confirmation = document.getElementsByClassName("applyConfirmation");
53-
}
54-
}
55-
56-
function refreshRateCalculations(thisObj) {
57-
const inputField = thisObj;
58-
rr = inputField.value;
59-
60-
handleRRConfirmation(rr);
61-
62-
if (rr >= 60) {
63-
var rrVRR = Math.round(rr * (1 - rr * 0.00028));
64-
const fpsFixed = document.getElementsByClassName("fpsFixed");
65-
const fpsVSync = document.getElementsByClassName("fpsVSync");
66-
const fpsVRR = document.getElementsByClassName("fpsVRR");
67-
68-
let valueVRR = rrVRR;
69-
let valueVSync = rr - 0.05;
70-
let valueFixed = rr;
71-
72-
let divider = 0;
73-
74-
if (rr > 120) {
75-
valueVRR = 120;
76-
valueVSync = largestCommonFactor(rr);
77-
if (valueVSync < 60) {
78-
valueVSync = "Invalid refresh rate - can't be cleanly divided!";
79-
}
80-
81-
valueFixed = valueVSync;
82-
divider = rr / valueVSync;
83-
84-
if (divider > 1) {
85-
let scanModeSetup = document.getElementsByClassName("scanModeSetup");
86-
for (let i = 0; i < scanModeSetup.length; i++) {
87-
scanModeSetup[i].style.display = "block";
88-
}
89-
90-
let scanModeDivider = document.getElementsByClassName("scanModeDivider");
91-
for (let i = 0; i < scanModeDivider.length; i++) {
92-
scanModeDivider[i].innerHTML = "1/" + divider;
93-
}
94-
}
95-
}
96-
else {
97-
let scanModeSetup = document.getElementsByClassName("scanModeSetup");
98-
for (let i = 0; i < scanModeSetup.length; i++) {
99-
scanModeSetup[i].style.display = "none";
100-
}
101-
}
102-
103-
for (let i = 0; i < fpsFixed.length; i++) {
104-
fpsFixed[i].innerHTML = valueFixed;
105-
}
106-
107-
for (let i = 0; i < fpsVSync.length; i++) {
108-
fpsVSync[i].innerHTML = valueVSync;
109-
}
110-
111-
for (let i = 0; i < fpsVRR.length; i++) {
112-
fpsVRR[i].innerHTML = valueVRR;
113-
}
114-
}
115-
}
116-
11738
function markActiveSection() {
11839
const sections = document.querySelectorAll('.section');
11940
const navLinks = document.querySelectorAll('.sidebar .pageLinks a');

sitemap.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
<url>
44
<loc>https://performance.moddinglinked.com/falloutnv.html</loc>
55
<priority>1.00</priority>
6-
<lastmod>2025-10-12</lastmod>
6+
<lastmod>2025-10-17</lastmod>
77
</url>
88
<url>
99
<loc>https://performance.moddinglinked.com</loc>

0 commit comments

Comments
 (0)