Skip to content

Commit 23f8568

Browse files
feat(TerminalCanvas): add reload mechanics and update controls for improved gameplay interaction
feat(HomeClient): enhance accessibility with localized aria labels and debug HUD translations
1 parent 982bd47 commit 23f8568

File tree

3 files changed

+141
-26
lines changed

3 files changed

+141
-26
lines changed

src/components/HomeClient.tsx

Lines changed: 20 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1806,7 +1806,7 @@ export default function HomeClient({
18061806
<main className="site-shell" ref={shellRef}>
18071807
{debugEnabled ? (
18081808
<div className="debug-hud">
1809-
{`scroll: ${debugHud.scroll.toFixed(3)}\nreveal: ${debugHud.reveal.toFixed(3)}\nfade: ${debugHud.fade.toFixed(3)}\nheroActive: ${debugHud.heroActive}`}
1809+
{`${t.ui.debugHud.scroll}: ${debugHud.scroll.toFixed(3)}\n${t.ui.debugHud.reveal}: ${debugHud.reveal.toFixed(3)}\n${t.ui.debugHud.fade}: ${debugHud.fade.toFixed(3)}\n${t.ui.debugHud.heroActive}: ${debugHud.heroActive}`}
18101810
</div>
18111811
) : null}
18121812
{!siteReady || isSwitching ? (
@@ -1915,7 +1915,7 @@ export default function HomeClient({
19151915
{languageMeta[language].label}
19161916
</button>
19171917
</div>
1918-
<div className="dock-socials" aria-label="Social links">
1918+
<div className="dock-socials" aria-label={t.ui.socialLinksLabel}>
19191919
{profile.socials.map((social, index) => {
19201920
const isEmail = social.href.startsWith("mailto:");
19211921
if (isEmail) {
@@ -2085,7 +2085,9 @@ export default function HomeClient({
20852085
{languageMeta.en.label}
20862086
</button>
20872087
</div>
2088-
<div className="sidebar-socials" aria-label="Social links">
2088+
<div
2089+
className="sidebar-socials"
2090+
aria-label={t.ui.socialLinksLabel}>
20892091
{profile.socials.map((social) => (
20902092
<a
20912093
key={social.label}
@@ -2210,7 +2212,9 @@ export default function HomeClient({
22102212
{languageMeta.en.label}
22112213
</button>
22122214
</div>
2213-
<div className="sidebar-socials" aria-label="Social links">
2215+
<div
2216+
className="sidebar-socials"
2217+
aria-label={t.ui.socialLinksLabel}>
22142218
{profile.socials.map((social) => (
22152219
<a
22162220
key={social.label}
@@ -2292,7 +2296,7 @@ export default function HomeClient({
22922296
<button
22932297
type="button"
22942298
className="hero-key-button hero-key-focus"
2295-
aria-label="Terminal input"
2299+
aria-label={t.hero.keys.terminalInputAria}
22962300
onPointerDown={(event) => {
22972301
event.preventDefault();
22982302
handleTerminalInputFocus();
@@ -2302,17 +2306,17 @@ export default function HomeClient({
23022306
<button
23032307
type="button"
23042308
className="hero-key-button hero-key-tab"
2305-
aria-label="Tab"
2309+
aria-label={t.hero.keys.tabAria}
23062310
onPointerDown={(event) => {
23072311
event.preventDefault();
23082312
handleVirtualKey("Tab", { focus: true });
23092313
}}>
2310-
Tab
2314+
{t.hero.keys.tabLabel}
23112315
</button>
23122316
<button
23132317
type="button"
23142318
className="hero-key-button hero-key-up"
2315-
aria-label="Arrow up"
2319+
aria-label={t.hero.keys.arrowUpAria}
23162320
onPointerDown={(event) => {
23172321
event.preventDefault();
23182322
handleVirtualKey("ArrowUp", { focus: false });
@@ -2322,7 +2326,7 @@ export default function HomeClient({
23222326
<button
23232327
type="button"
23242328
className="hero-key-button hero-key-left"
2325-
aria-label="Arrow left"
2329+
aria-label={t.hero.keys.arrowLeftAria}
23262330
onPointerDown={(event) => {
23272331
event.preventDefault();
23282332
handleVirtualKey("ArrowLeft", { focus: false });
@@ -2332,7 +2336,7 @@ export default function HomeClient({
23322336
<button
23332337
type="button"
23342338
className="hero-key-button hero-key-right"
2335-
aria-label="Arrow right"
2339+
aria-label={t.hero.keys.arrowRightAria}
23362340
onPointerDown={(event) => {
23372341
event.preventDefault();
23382342
handleVirtualKey("ArrowRight", { focus: false });
@@ -2342,7 +2346,7 @@ export default function HomeClient({
23422346
<button
23432347
type="button"
23442348
className="hero-key-button hero-key-down"
2345-
aria-label="Arrow down"
2349+
aria-label={t.hero.keys.arrowDownAria}
23462350
onPointerDown={(event) => {
23472351
event.preventDefault();
23482352
handleVirtualKey("ArrowDown", { focus: false });
@@ -2354,20 +2358,20 @@ export default function HomeClient({
23542358
className={`hero-key-button hero-key-mod hero-key-ctrl${
23552359
mobileModifiers.ctrl ? " is-active" : ""
23562360
}`}
2357-
aria-label="Ctrl modifier"
2361+
aria-label={t.hero.keys.ctrlAria}
23582362
aria-pressed={mobileModifiers.ctrl}
23592363
onPointerDown={(event) => {
23602364
event.preventDefault();
23612365
toggleMobileModifier("ctrl");
23622366
}}>
2363-
Ctrl
2367+
{t.hero.keys.ctrlLabel}
23642368
</button>
23652369
<button
23662370
type="button"
23672371
className={`hero-key-button hero-key-mod hero-key-shift${
23682372
mobileModifiers.shift ? " is-active" : ""
23692373
}`}
2370-
aria-label="Shift modifier"
2374+
aria-label={t.hero.keys.shiftAria}
23712375
aria-pressed={mobileModifiers.shift}
23722376
onPointerDown={(event) => {
23732377
event.preventDefault();
@@ -2380,13 +2384,13 @@ export default function HomeClient({
23802384
className={`hero-key-button hero-key-mod hero-key-alt${
23812385
mobileModifiers.alt ? " is-active" : ""
23822386
}`}
2383-
aria-label="Alt modifier"
2387+
aria-label={t.hero.keys.altAria}
23842388
aria-pressed={mobileModifiers.alt}
23852389
onPointerDown={(event) => {
23862390
event.preventDefault();
23872391
toggleMobileModifier("alt");
23882392
}}>
2389-
Alt
2393+
{t.hero.keys.altLabel}
23902394
</button>
23912395
</div>
23922396
) : null}

src/components/terminal/TerminalCanvas.tsx

Lines changed: 75 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1066,6 +1066,8 @@ export default function TerminalCanvas({
10661066
const doomBombsRef = useRef(2);
10671067
const doomScoreRef = useRef(0);
10681068
const doomCooldownRef = useRef(0);
1069+
const doomReloadRef = useRef(0);
1070+
const doomReloadMaxRef = useRef(0);
10691071
const doomGameOverRef = useRef(false);
10701072
const doomMiniMapRef = useRef(true);
10711073
const doomBobRef = useRef(0);
@@ -1238,6 +1240,7 @@ export default function TerminalCanvas({
12381240
hit: "İSABET",
12391241
noBombs: "BOMBA YOK",
12401242
boom: "PATLAMA",
1243+
reload: "ŞARJÖR",
12411244
doorOpen: "KAPI AÇILDI",
12421245
doorClose: "KAPI KAPANDI",
12431246
noDoor: "KAPI YOK",
@@ -1282,7 +1285,7 @@ export default function TerminalCanvas({
12821285
controls1:
12831286
"W/S: hareket A/D: kay ←/→: dön Shift: koş Boşluk: saldırı",
12841287
controls2:
1285-
"1: yumruk/testere 2: tabanca 3: pompalı 4: minigun 5: roketatar B: bomba E: etkileşim M: harita H: ipucu R: reset Q: çıkış",
1288+
"1: yumruk/testere 2: tabanca 3: pompalı 4: minigun 5: roketatar B: bomba E: etkileşim R: şarjör M: harita H: ipucu Shift+R: reset Q: çıkış",
12861289
gameOver: "ÖLDÜN - R: yeniden",
12871290
},
12881291
en: {
@@ -1298,6 +1301,7 @@ export default function TerminalCanvas({
12981301
hit: "HIT",
12991302
noBombs: "NO BOMBS",
13001303
boom: "BOOM",
1304+
reload: "RELOAD",
13011305
doorOpen: "DOOR OPEN",
13021306
doorClose: "DOOR CLOSED",
13031307
noDoor: "NO DOOR",
@@ -1342,7 +1346,7 @@ export default function TerminalCanvas({
13421346
controls1:
13431347
"W/S: move A/D: strafe ←/→: turn Shift: run Space: attack",
13441348
controls2:
1345-
"1: fists/saw 2: pistol 3: shotgun 4: chaingun 5: launcher B: bomb E: interact M: map H: hint R: reset Q: quit",
1349+
"1: fists/saw 2: pistol 3: shotgun 4: chaingun 5: launcher B: bomb E: interact R: reload M: map H: hint Shift+R: reset Q: quit",
13461350
gameOver: "YOU DIED - R: restart",
13471351
},
13481352
} as const;
@@ -2312,6 +2316,8 @@ export default function TerminalCanvas({
23122316
doomHintRef.current = null;
23132317
doomHintWindowRef.current = true;
23142318
doomCooldownRef.current = 0;
2319+
doomReloadRef.current = 0;
2320+
doomReloadMaxRef.current = 0;
23152321
doomGameOverRef.current = false;
23162322
doomBobRef.current = 0;
23172323
if (resetStats) {
@@ -2726,6 +2732,9 @@ export default function TerminalCanvas({
27262732
if (doomGameOverRef.current) {
27272733
return;
27282734
}
2735+
if (doomReloadRef.current > 0) {
2736+
return;
2737+
}
27292738
if (doomCooldownRef.current > 0) {
27302739
return;
27312740
}
@@ -3034,6 +3043,38 @@ export default function TerminalCanvas({
30343043
doomMessageRef.current = doomText("boom");
30353044
}, [doomText]);
30363045

3046+
const reloadDoom = useCallback(() => {
3047+
if (getDoomBootProgress() < 1) {
3048+
return;
3049+
}
3050+
if (doomGameOverRef.current) {
3051+
beginDoomBoot();
3052+
resetDoom();
3053+
return;
3054+
}
3055+
if (doomReloadRef.current > 0) {
3056+
return;
3057+
}
3058+
const weapon = doomWeaponRef.current;
3059+
if (weapon === "fist" || weapon === "chainsaw") {
3060+
doomMessageRef.current = doomText("ready");
3061+
return;
3062+
}
3063+
const duration =
3064+
weapon === "pistol"
3065+
? 18
3066+
: weapon === "shotgun"
3067+
? 26
3068+
: weapon === "chaingun"
3069+
? 22
3070+
: weapon === "launcher"
3071+
? 28
3072+
: 20;
3073+
doomReloadRef.current = duration;
3074+
doomReloadMaxRef.current = duration;
3075+
doomMessageRef.current = doomText("reload");
3076+
}, [beginDoomBoot, doomText, getDoomBootProgress, resetDoom]);
3077+
30373078
const openDoomDoor = useCallback(() => {
30383079
const map = doomMapRef.current;
30393080
if (!map.length) {
@@ -3159,6 +3200,13 @@ export default function TerminalCanvas({
31593200
if (doomCooldownRef.current > 0) {
31603201
doomCooldownRef.current -= 1;
31613202
}
3203+
if (doomReloadRef.current > 0) {
3204+
doomReloadRef.current -= 1;
3205+
if (doomReloadRef.current <= 0) {
3206+
doomReloadRef.current = 0;
3207+
doomReloadMaxRef.current = 0;
3208+
}
3209+
}
31623210
impulse.move *= 0.82;
31633211
impulse.strafe *= 0.82;
31643212
impulse.turn *= 0.7;
@@ -9279,7 +9327,16 @@ export default function TerminalCanvas({
92799327
const weaponW = clamp(Math.floor(viewW * 0.46), 170, 320);
92809328
const weaponH = clamp(Math.floor(viewH * 0.22), 78, weaponMaxH);
92819329
const weaponX = Math.floor(viewX + (viewW - weaponW) / 2 + bobX);
9282-
const weaponY = Math.floor(hudY - weaponH - 6 + bobY - recoil * 10);
9330+
const reloadMax = doomReloadMaxRef.current;
9331+
const reloadRemaining = doomReloadRef.current;
9332+
const reload =
9333+
reloadMax > 0 ? clamp(reloadRemaining / reloadMax, 0, 1) : 0;
9334+
const reloadPhase = 1 - reload;
9335+
const reloadDrop = Math.sin(reloadPhase * Math.PI);
9336+
const reloadY = reloadDrop * weaponH * 0.22;
9337+
const weaponY = Math.floor(
9338+
hudY - weaponH - 6 + bobY - recoil * 10 + reloadY,
9339+
);
92839340
const weapon = doomWeaponRef.current;
92849341
const attack = clamp(doomMuzzleRef.current / 14, 0, 1);
92859342
ctx.save();
@@ -9629,8 +9686,8 @@ export default function TerminalCanvas({
96299686
);
96309687
}
96319688

9632-
const labelFont = Math.max(9, Math.floor(hudHeight * 0.18));
9633-
const valueFont = Math.max(16, Math.floor(hudHeight * 0.38));
9689+
const labelFont = Math.max(9, Math.floor(hudHeight * 0.16));
9690+
const valueFont = Math.max(14, Math.floor(hudHeight * 0.33));
96349691
const labelY = hudY + Math.floor(hudHeight * 0.14);
96359692
const valueY = hudY + Math.floor(hudHeight * 0.4);
96369693
const statPad = Math.floor(sectionPadding * 0.4);
@@ -9686,7 +9743,7 @@ export default function TerminalCanvas({
96869743
ctx.fillStyle = "#f4d35e";
96879744
ctx.fillText(String(bombs).padStart(2, "0"), bombsX + statPad, valueY);
96889745

9689-
ctx.font = `${Math.max(9, Math.floor(hudHeight * 0.18))}px "JetBrains Mono", ui-monospace, SFMono-Regular, Menlo, monospace`;
9746+
ctx.font = `${Math.max(9, Math.floor(hudHeight * 0.16))}px "JetBrains Mono", ui-monospace, SFMono-Regular, Menlo, monospace`;
96909747
ctx.fillStyle = "rgba(255,255,255,0.55)";
96919748
const weaponKeyMap: Record<string, string> = {
96929749
fist: "weaponFist",
@@ -9823,12 +9880,12 @@ export default function TerminalCanvas({
98239880
const infoY = Math.min(hudY - 16, viewY + viewH - 16);
98249881
const hintWindowVisible = doomHintWindowRef.current;
98259882
if (hintWindowVisible) {
9826-
const hintFont = Math.max(8, Math.floor(headerSize * 0.54));
9883+
const hintFont = Math.max(8, Math.floor(headerSize * 0.46));
98279884
const hintLineHeight = Math.max(12, Math.floor(hintFont * 1.35));
98289885
const panelPaddingX = 12;
98299886
const panelPaddingY = 10;
98309887
const colGap = 14;
9831-
const desiredPanelW = Math.min(Math.floor(viewW * 0.72), 520);
9888+
const desiredPanelW = Math.min(Math.floor(viewW * 0.84), 640);
98329889
const panelW = clamp(
98339890
desiredPanelW,
98349891
Math.min(240, Math.floor(viewW)),
@@ -10687,6 +10744,9 @@ export default function TerminalCanvas({
1068710744
return true;
1068810745
}
1068910746
if (lower === "r") {
10747+
if (mode === "doom" && !event.shiftKey) {
10748+
return false;
10749+
}
1069010750
if (mode === "snake") {
1069110751
resetSnake();
1069210752
placeSnakeFood();
@@ -11246,6 +11306,12 @@ export default function TerminalCanvas({
1124611306
event.preventDefault();
1124711307
return true;
1124811308
}
11309+
if (lower === "r") {
11310+
reloadDoom();
11311+
dirtyRef.current = true;
11312+
event.preventDefault();
11313+
return true;
11314+
}
1124911315
if (lower === "e") {
1125011316
interactDoom();
1125111317
dirtyRef.current = true;
@@ -11654,6 +11720,7 @@ export default function TerminalCanvas({
1165411720
moveEditorCursor,
1165511721
interactDoom,
1165611722
shootDoom,
11723+
reloadDoom,
1165711724
throwDoomBomb,
1165811725
hasChessLegalMove,
1165911726
isChessInCheck,

0 commit comments

Comments
 (0)