Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
135 changes: 0 additions & 135 deletions .github/workflows/osu-counters.yml

This file was deleted.

43 changes: 23 additions & 20 deletions index.html
Original file line number Diff line number Diff line change
@@ -1,23 +1,26 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link rel="stylesheet" href="style.css" />
</head>
<body>
<div id="container" class="hidden">
<!-- now added by js -->
<!-- <div class="sd hidden"></div> -->
<div class="arrow-container hidden">
<div class="arrow hidden"></div>
</div>
<div class="main hidden">
<div class="colors-container hidden"><!-- THIS IS A FLEX CONTAINER --></div>
<div class="tick-container hidden"></div>
<div class="bar hidden"></div>
</div>

<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link rel="stylesheet" href="style.css" />
</head>

<body>
<div id="container" class="hidden">
<!-- now added by js -->

<div class="arrow-container hidden">
<div class="arrow hidden"></div>
</div>
<script type="module" src="src/index.ts"></script>
</body>
</html>
<div class="main hidden">
<div class="colors-container hidden"><!-- THIS IS A FLEX CONTAINER --></div>
<div class="tick-container hidden"></div>
<div class="bar hidden"></div>
</div>
</div>
<script type="module" src="src/index.ts"></script>
</body>

</html>
2 changes: 1 addition & 1 deletion metadata.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
Usecase: Ingame Overlay, OBS Overlay
Name: Custom Hit Error Bar
Version: 3.6.0
Version: 3.7.0
Author: breadles5
CompatibleWith: Tosu
Resolution: 656x90
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"name": "custom-hit-error-bar",
"author": "breadles",
"license": "GPL-3.0-only",
"version": "3.6.0",
"version": "3.7.0",
"type": "module",
"scripts": {
"build:prod": "vite build --mode production",
Expand Down
10 changes: 1 addition & 9 deletions settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -175,14 +175,6 @@
"options": [],
"value": 800
},
{
"uniqueID": "showSD",
"type": "checkbox",
"title": "Show UR (ms)",
"description": "",
"options": [],
"value": false
},
{
"uniqueID": "isRounded",
"type": "number",
Expand All @@ -207,4 +199,4 @@
"options": [],
"value": "16.5,64,97,127,151"
}
]
]
50 changes: 34 additions & 16 deletions src/calculation/statistics.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,24 +3,42 @@ export const average = (arr: number[]): number => {
return arr.reduce((a, b) => a + b, 0) / arr.length;
};

export const standardDeviation = (arr: number[]): number => {
if (!arr || arr.length === 0) return 0;
const avg = average(arr);
const squareDiffs = arr.map((value) => {
const diff = value - avg;
const sqrDiff = diff * diff;
return sqrDiff;
});
const avgSquareDiff = average(squareDiffs);
return Math.sqrt(avgSquareDiff);
};
// Reusable buffer for median calculation to avoid allocations
let medianBuffer: number[] = new Array(200); // Start with a reasonable size

export const median = (arr: number[]): number => {
if (!arr || arr.length === 0) return 0;
const sortedArr = [...arr].sort((a, b) => a - b);
const middle = Math.floor(sortedArr.length / 2);
if (sortedArr.length % 2 === 0) {
return (sortedArr[middle - 1] + sortedArr[middle]) / 2;

// Ensure buffer is large enough
if (medianBuffer.length < arr.length) {
medianBuffer = new Array(arr.length * 2);
}

// Copy data to buffer
for (let i = 0; i < arr.length; i++) {
medianBuffer[i] = arr[i];
}

// Sort valid portion of buffer
// using subarray is safer but creates a view, let's just sort the slice logic manually or use subarray which is cheap
// Array.prototype.sort mutates. We only want to sort the first N elements.
// JS arrays are dynamic, but we want to avoid GC.
// Using a subarray (slice) creates a new array (alloc).
// subarray() on TypedArray is cheap, but these are number[] (Objects).
// So we must fallback to: copy to buffer -> sort buffer -> take middle.
// But Array.prototype.sort sorts the *entire* array.
// We can just use a shared array that we don't care about the tail of, IF we can tell sort to stop... we can't.
// ACTUALLY: The best way for zero-alloc sort on a subset of a generic Array is tricky without writing a custom QuickSort.
// Given the constraints and standard JS engine optimization:
// If we just trim the length of the reused array, it might realloc internally if it grows, but shrinking is usually fine.

// Let's resize the buffer length. This is generally optimized in V8.
medianBuffer.length = arr.length;
medianBuffer.sort((a, b) => a - b);

const middle = Math.floor(medianBuffer.length / 2);
if (medianBuffer.length % 2 === 0) {
return (medianBuffer[middle - 1] + medianBuffer[middle]) / 2;
}
return sortedArr[middle];
return medianBuffer[middle];
};
2 changes: 1 addition & 1 deletion src/calculation/tickManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ export class TickImpl implements Tick {
});
}

this.position = (hitError / cache.rate) * 2;
this.position = hitError * 2;
this.timestamp = Date.now();
this.setClassNames(); // Updates classNames (colors, base class) and calls updateElement
}
Expand Down
Loading