aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPinapelz <yukais@pinapelz.com>2026-04-16 17:22:27 -0700
committerPinapelz <yukais@pinapelz.com>2026-04-16 17:22:27 -0700
commit5709b7323ca39dd1397720fc0b13a587638967f1 (patch)
tree59e643ee6243b2d54a24ff121f6f615a359b3371
parentd5fe045b361a3735509bfa2549efa0bd185bc7de (diff)
add estimated CPS needed to type current line
-rw-r--r--src/app/game/game.utils.ts4
-rw-r--r--src/app/game/page.styles.ts14
-rw-r--r--src/app/game/page.tsx34
3 files changed, 40 insertions, 12 deletions
diff --git a/src/app/game/game.utils.ts b/src/app/game/game.utils.ts
index 6177d2c..4c99c55 100644
--- a/src/app/game/game.utils.ts
+++ b/src/app/game/game.utils.ts
@@ -42,6 +42,10 @@ export function parseLrcLines(lrcText: string): GameLine[] {
return result;
}
+export function calculateCPSNeeded(text: string, seconds: number): number {
+ return text.length / seconds;
+}
+
export function formatTime(ms: number): string {
const s = Math.max(0, Math.floor(ms / 1000));
return `${Math.floor(s / 60)}:${String(s % 60).padStart(2, "0")}`;
diff --git a/src/app/game/page.styles.ts b/src/app/game/page.styles.ts
index e8a2678..da45d8a 100644
--- a/src/app/game/page.styles.ts
+++ b/src/app/game/page.styles.ts
@@ -149,6 +149,7 @@ export const UpcomingText = styled.p`
font-size: 20px;
color: rgba(255, 255, 255, 0.30);
font-weight: 400;
+ font-family: "Inter", "Segoe UI", "Helvetica Neue", Arial, sans-serif;
min-height: 28px;
white-space: nowrap;
overflow: hidden;
@@ -164,11 +165,18 @@ export const CurrentWrap = styled.div`
gap: 10px;
`;
+export const LineTimingRow = styled.div`
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ gap: 12px;
+`;
+
export const LineTimingMeta = styled.div`
display: flex;
align-items: center;
- justify-content: flex-end;
- font-size: 11px;
+ justify-content: flex-start;
+ font-size: 13px;
letter-spacing: 1px;
text-transform: uppercase;
color: rgba(255, 255, 255, 0.45);
@@ -219,7 +227,7 @@ export const CharBox = styled.span<{
justify-content: center;
font-size: 36px;
font-weight: 700;
- font-family: monospace;
+ font-family: "Inter", "Segoe UI", "Helvetica Neue", Arial, sans-serif;
padding: 0 3px;
border-radius: 4px;
transition: all 0.08s ease;
diff --git a/src/app/game/page.tsx b/src/app/game/page.tsx
index 7e6e9c3..aa953a7 100644
--- a/src/app/game/page.tsx
+++ b/src/app/game/page.tsx
@@ -30,6 +30,7 @@ import {
CurrentWrap,
LineTimingMeta,
LineTimingValue,
+ LineTimingRow,
LineTimingBar,
LineTimingFill,
CharRow,
@@ -66,7 +67,7 @@ import {
HomeBtn,
} from "./page.styles";
import { gReducer, initialGState } from "./game.stat";
-import { formatTime, parseLrcLines } from "./game.utils";
+import { formatTime, parseLrcLines, calculateCPSNeeded } from "./game.utils";
type GamePhase = "idle" | "countdown" | "playing" | "paused" | "finished";
@@ -82,6 +83,7 @@ function GameInner() {
const [currentMs, setCurrentMs] = useState(0);
const [lineTimingPct, setLineTimingPct] = useState(0);
const [lineRemainingMs, setLineRemainingMs] = useState(0);
+ const [currentLineTime, setCurrentLineTime] = useState(0);
const [duration, setDuration] = useState(0);
const [progressPct, setProgressPct] = useState(0);
const [gameDurationMs, setGameDurationMs] = useState(0);
@@ -169,6 +171,7 @@ function GameInner() {
lineAnimRef.current = { startMs: 0, endMs: 0, startPerf: 0 };
setLineTimingPct(0);
setLineRemainingMs(0);
+ setCurrentLineTime(-1);
return;
}
const start = gameLines[idx].millisecond;
@@ -179,7 +182,9 @@ function GameInner() {
startPerf: performance.now(),
};
setLineTimingPct(0);
- setLineRemainingMs(Math.max(0, end - start));
+ const currentLineTime = end - start;
+ setLineRemainingMs(Math.max(0, currentLineTime));
+ setCurrentLineTime(Math.max(currentLineTime, currentLineTime));
}, [g.displayedLineIdx, gameLines]);
useEffect(() => {
@@ -561,12 +566,23 @@ function GameInner() {
</UpcomingText>
</UpcomingWrap>
<CurrentWrap style={{ position: "relative" }}>
- <LineTimingMeta>
- Time left:{" "}
- <LineTimingValue>
- {Math.max(0, lineRemainingMs / 1000).toFixed(1)}s
- </LineTimingValue>
- </LineTimingMeta>
+ <LineTimingRow>
+ <LineTimingMeta>
+ Time left:{" "}
+ <LineTimingValue>
+ {Math.max(0, lineRemainingMs / 1000).toFixed(1)}s
+ </LineTimingValue>
+ </LineTimingMeta>
+ <LineTimingMeta>
+ Estimated CPS:{" "}
+ <LineTimingValue>
+ {calculateCPSNeeded(
+ gameLines[g.displayedLineIdx].content,
+ currentLineTime / 1000
+ ).toFixed(1)}
+ </LineTimingValue>
+ </LineTimingMeta>
+ </LineTimingRow>
<LineTimingBar>
<LineTimingFill $pct={lineTimingPct} />
</LineTimingBar>
@@ -625,7 +641,7 @@ function GameInner() {
</CharRow>
{clearShowing && <ClearToast>CLEAR!</ClearToast>}
<CompletedLineFade>
- {g.lineCompleted ? "Cleared - waiting for next line..." : ""}
+ {g.lineCompleted ? "Cleared - waiting for next line..." : gameLines[g.displayedLineIdx].content}
</CompletedLineFade>
</CurrentWrap>
</>
send patches to the email below
yukais@pinapelz.com
include the subject [PATCH repo_name]
pinapelz.com
homepage