From c2ecb0173c7acaca94a4d9fad665f1fa9d101ef2 Mon Sep 17 00:00:00 2001 From: Mohamed Date: Sun, 9 Aug 2026 01:52:53 +0300 Subject: [PATCH 1/2] Working sound effects system --- .../client/public/sounds/standard/Capture.mp3 | Bin 0 -> 3432 bytes apps/client/public/sounds/standard/Castle.mp3 | Bin 0 -> 5353 bytes apps/client/public/sounds/standard/Check.mp3 | Bin 0 -> 6121 bytes .../public/sounds/standard/Game-End.mp3 | Bin 0 -> 5353 bytes .../public/sounds/standard/GenericNotify.mp3 | Bin 0 -> 8011 bytes apps/client/public/sounds/standard/Move.mp3 | Bin 0 -> 2547 bytes .../client/public/sounds/standard/Promote.mp3 | Bin 0 -> 4969 bytes apps/client/src/hooks/game/useChessGame.ts | 6 ++- apps/client/src/hooks/game/useComputerGame.ts | 7 ++- apps/client/src/services/sfx/index.ts | 46 ++++++++++++++++++ apps/client/tsconfig.json | 3 +- apps/client/vite.config.ts | 1 + 12 files changed, 59 insertions(+), 4 deletions(-) create mode 100644 apps/client/public/sounds/standard/Capture.mp3 create mode 100644 apps/client/public/sounds/standard/Castle.mp3 create mode 100644 apps/client/public/sounds/standard/Check.mp3 create mode 100644 apps/client/public/sounds/standard/Game-End.mp3 create mode 100644 apps/client/public/sounds/standard/GenericNotify.mp3 create mode 100644 apps/client/public/sounds/standard/Move.mp3 create mode 100644 apps/client/public/sounds/standard/Promote.mp3 create mode 100644 apps/client/src/services/sfx/index.ts diff --git a/apps/client/public/sounds/standard/Capture.mp3 b/apps/client/public/sounds/standard/Capture.mp3 new file mode 100644 index 0000000000000000000000000000000000000000..ab51d763de8c3711e89ad7fbd23e99c360b3c062 GIT binary patch literal 3432 zcmeH}YgAKL7ROJXLI?-}HHgMb!ZU^#9?=K_fk5Ql$g4qPO&}41m7w6;t_ctE6)Xb^ zQPF}521+%~=#+rfpn(A4rKM^WtS_L7C?n8HQ8Iyyoz>0^Um=9((5NIH2|Rout~#;Aprc<03fG# ztn0|#mc_*zYW7Qo_62M(R}g^DUB0|EL?d`3i_Ul}t~~1Gt5s2-wwc24W@;H0dO}F! z^Bm0fXq*sT1%%x4)3znr^7I=;OG8g@o4J|;AkhqdIRv!B?aj>Vx9U#+TkWPVzPkD~an5%CMbx}-4c+4B~8 z?NYR`l<5n;$sq8%mj5LpHQc?Hq7EPiCS<{zn=xp=ujwZ(RZ{Ua^*NZ zS2BBGM9=G%)M_bfM2BB$KIwB9=xP<+9_rDSPURz7wrhfFrTfK@Z;~nVh4X&%e zA(>3W%8Tjw1ppw{?};(xJg$xMgk{IL6qV=TTe^pP_N{2-*Xk~E$ljQ&_4U+B61HhR zj_p|JggKmtD_n_kb=q0nwBvdf>#{DZtWn5o8Ge0}#M6~MX@2abvE-`LIb__?`B3q8 zvfGi+3>&5g-)fD1LaKQVuy4lgF6BuPkItqn^U*NdARF|-K8pyNVi;pDL%=kA4h=`! zZq8kXWLs5z3t#EVQABCGOzK{QQE=wD0c(EVNDFIV5yMHAa9{%Bu~n@>ayUa?V6sno ziXX{t0oE{Z#A|zhe2?A2axv|bc_gJq_Ze(})c0eFp7Nq|V}EI@BRk|uY3C0BCmz~f zY1oOx*eXHMb5Y}>ibo+Vn5MmKM2vTP-9#r6MEUrb{;>i^^D`(#VS;5O<+k%l)}|56 zRWQ5YJ)zGNqyJfni3q8VhRp$x39=!vnPo+Rn{_Xs1?-jcqZ8FW(5zXFEU3(53r7wS z@jL{g>$|bw9FT=2TM`j!E3&=R=UOL0q%Ql&C4HweK@>GC1NG+<>T#X;{JOMW?Kao3 ziAo(gk+}71gqsd`M}JDcXf*(9hr9=a0DvEm`JHe-Xrd)QcC-ty|2C`gqvh2eZ%jI- zZo`0-!0UBW-Iu}#@Mjm%)ghwm3-Yi9W-D@)-C0TASIljE5SWOa@})&8L1(`${pop& zY*Zxj@*sqPBI}j6-J@tS>;a5lc+4D>MT$Fw;#13V?_hu`VUsj(HhxJFmEw_AW<{h! z1&|u&;voEM)dMss6yC4tIoxdp$20lqEIm8FJu{Za6@9-c^+y*H=xy2Rx|{HV)fO0W zYpoo;hB@5i_5_uq*6m?JC@Hl_QA1&(&5HdEWb&d*q0Y+rI2X zl3w4m(Y%4s>q`&QkLV{?Ux{zpGDuo$fAfaZME6M2F1^2gaD>a*B3EHHg+(&T0DakO zKr};B$(bc6o`USHwE1dI;3;nWm}+T!t+H+ITKKiz;=&8b79_%|q7qNO^+j1*DJL_t z@pfru_kyc8P52jm!<`>DMoubH_r^;~m)4o0uK9nh=LO;U$P=Sdq+bkb>IdBh^Un;@ z#@nT^hA++zDuMVU+t>;Td4+p++$(WEX|?fho_7Cn^61NjJq5eJ&Y7RmG`Qv{W^{UmgN(x zSd-wJ`5qjl)}lpDdCJG$QDM$wF2A-K7^(hwLy*F=!8Z5;a$aNKaQeC0z*HS>?4)^u zF^3wTqjA6H(YQateoH2B*;ERkGel14;Vv6k5k=wsYsl&uqMu-DegS6kOUr9)aaD^8 z`{;SLHSZalv+mUg>%1qV!Tcd1^%FGBPtp*|2IuF#G+507?Jw8O|kA$46 z1SWt+=4_1>I4FvciS~PyHZu(L9=G32eM;v+R)g9cC$oiI>D3rz@Ko2Ko@UsrB6YeFgO)0cPm?r_KyF>UVDct9|6xw5_*x|QA(%=1f@$+ zL7EgBMZp4spnp)XgNVRBaP`c&FZc00-QRxL>uYP){N|gzXBNpojTzVjB0(lv=xXAR5vvt84}Og z`T=AEoBa&%z0Imv6)h#Kx{|8Ozf*|p&4&8=Q~%dtm7}Vf*nI%9tu1lyLgHwUkx%7XAbHoBW@_{}GV_yaM-@_R;`c0D!;&Vt>H=h42@q zaDcBt|NO5`K&XlB-C1Ty;BM;(pa}qcnnR18I97GS$IjkQ!FsPjFnouf5#QZO7ixLh z1I~iqe(KIXM)K1D{?6T`l5lksm+78Z6Q z(f>|9Zsv@J5G0a}n%BoRfvmd(IOB(tfG#!+spEB|+{nRR38Dczj zKg9$E{+dXR2{nV?*y@?2RQD+doF6AC_kiyMPDk!Ar#=*F*a83!96);^x##rK#lpzc z+Tp}C>nFD1#RaZLfsDtB1Cc5jFmDjQCDZexu9^qJ2MFRIC-Z5?IHMacOpWvH`)8*y zr5M_T>jF>|zLT_&3LKC+LWIi%_Z9$N>Od0Uen^iZN0zr^nV?O?*Zb0!)lrsdivACz zkD{nn@6dUk2|a~d4HsyumD#Ho*A))vWNz#bbEl7N*X#9&I-5-2e!~f31TZ%5#Y?=6 zt*~>f;I=}u+?P`ddE2GlyAJ_C0Klx8@BlU^T3+RhHl`iAd*=59NL`IuBiW|zWX$=< z_3ZX+K8L6a!QU7#%}`TkZv*F`kV~Rcv?}^t8N~?A_cmlPh&2MoxiSr@?jg zg5A$A$`a&pgdp5?aeQ3`6EhM(4V7;zGEq$nYE)6$n9RKB)=6j?*m6=y*;0DDIJ+%#LYYVkE$Bez6FQZ&znjBA|kDX!NprMR|f z+*zn$Jk6D};7;YMy8irLrFww{E7cGRN4FPe*cFkh;OFb9J9hC$H@<(X>$)7(zvM+dafFXH8i_znT?yER zJ~NKV7Wh(qW^*@=nak3@ zR9856PK=cfB9JIrmUW6kd-+xdA8_i^$Vg$KrM0<1Z>Wnz#grN@&k$}Q z%27O|PQd5;u0B3N{h^qWFi6PL)BlvD-KHJx8ESfJ2_#R1MK(#j4|~;qOWyu-jHzRl z8(KKyWXp@w?XL`Is&NawsXWoV*osQ_btmT_l@|F^kojqJq&R-XO`6SaJj-QU&y5*y z_aoBqy! zL~Ht;ww@^lypJH?+WI~Ftn2dUV_@mAp)$RH{^viWmH0gh+z><@19z1ey+V)y1Qd|s zZ*yuUiQqUJOIkJA=N})u+5|88KI#2rzHr{pWj$Y?_}hD?Pf#1|Dg1P^V{x<0n{3?b zQX?*`q-8oiH1u}0lcy^1F(@nQRI{xEJ?qpvtS>6m>Lq+W{m@x)(fp(;PeL9}fUzdWv4;Mh3e_4)?~pqq0*?qT1lDpSYj$Zg+RV z`G?)5>YaA8#pg<$8|FTOVrRQACLh9E%n!4%XY119>5Mja&cJq!t*gOEpL~l|4|q<- z4fbe&?YP_5_-Z*=QpI4_LAUAcf(hh0cl&d&1zcTQc^rGcLW##J8Wx<_CMxuz;%d=D z>y1!v_2Upio=gm{0F&R%}H6tbTTCyz!h0be&+NH=1ubb z7#KkpFx3OWv2}E68~7CuC)iGc;0~ToE7H0AsU)>0?nfdFRsL3}FGtig+LCh_2fL7v z&5Er=01^-aB$W`IBw{H973H{V<=CVZpjh1&HUH9dB-)z9tNG7Z^1}*puVL|!S1|tS z7(DmN9kv}FW_K%T$C<1YPTes>I}f?@U(EZKmaoH&5AVQ!Bz5zX((fe*F3yidG+5;& zUAU3XuXslBu*NIRd`jK%jJ4%aXTob8tBylYJycmMtrNKIJAYCiJikJW$H7<6+D_%`m1nt0N)GYQrqIKn1O#8Xxr=t{d zW)a5cJRll=wdac1cx*lmui%j?W*bqeSwg7MK?9|G23^NEvj!*HC**+SJB-@uP$(e|dBnHh6}lzM+*J64&-rA(Jf5`XsW<@;}qAmT9}`HIp#RJgN375DG|0p`9g zv|$drSmsGaQj<5-oZQ>QL)Kg%6;CEBq{;Swy>Na0@(UMW0 z*V%iQ<3r-YzcsmT5z=bY(Hdrk4$_kZM={C6U+vUy{XTW&Q*wZ*q$40BEfo(}#dFXp zF7ffEw`sNYBj}C~+|?=00%^TRk=ZlFuF-vLU9k|u*&9lt&9c^`KV{yKjTE&=qN|fi z=G2h#qFd|V>6}p}_v1^ziC%8|Oo(0MlxQW^dwiN|OmejvQPWO)=asvnre$O(B9fHV zwo;F4*fhMDot@2yr8XWJ39?8CJ8yYXPq2JgIKir!izlZ2(#p;grej7wL8sif3fzzm znIpeB_B|;zKnlqNvquGyb$u)p!|piCeXY_?9fG7hl0ysdwSVQabYE?J^ot^L@(Rq* zsX$28Av>x}^{|c5V1)!&t;fdpI>VG}gFSX43f#@30xYwY#N%^^h9$ESvMwQ-{L!J3 zgl-nc1@sh*8Kt)Gp9kpkL6XMbi*{HK3iZ2r6mq<-<}+(-jJ6g)l4$8Oi7WYa--ty2 z4o(RWy&x;2B`o>g7Hb&LxS2VlNZq*h`a26=T!R>Odq)IZu^}WgnXV;svD8B&QiyAK z`aosx>D(aJ0*8>-b^=##U2D~7ye$uj364jNF5jPcV*K0;Mp`KG8B7<;>lw3kM`)3? zY(F2Qbj`#fC~0jCU`;trS>^+ZpLxs@W=6xMh~BIttnd_%0!)NBkAgUMKi#VE( zl``J158yhzj>Ym@MVReEX~8CGaVekRHn|s^K5zG*O8By5n5_^P9QpmzkQC9RIL2(u z2hpVeV>B*qhewx2|0;QdK#Vbt!k-OX=S~G*DzdZrpSfbpS@bZR=bVF#_5ofmekh}q z4u_=_PTLzJ<~onGZbsg_7~4NI7oDWt2Vvd!FAPlR@eM!4V1q2Pfb$MJ;MB%7S^kW7s+ zV&mz~F4s5J?s$pl&f#i1Zx$x;dGYnfac7EJfX%SMEly5skW#?0Z%GtootX}i$hnpJzt0Y(c8kz&!u%sLrBTY&PqaTZ=KCBH3(d?T(vRPT|IQ2-$Xo%EGZ>=y?$-Q72oXhA>*_>oo?JF zZ$E@!G;8HMb4K&vtj`NM8r5VbE8C-OyY5H$C3uW}{J`?Sxd za3_o%BlucoGBvqQ#zR9@n&*p!ys>sB+g+@6i4}&V8XS5VCjyM+@B3GQe>=>t&jc6a zF^XPxqhK^(WOJS~GFEu8qVi~Z3PXf>GqpJ+>!`s80X9#TQ;2igWx+>cTih@@ydj+B zwJ&x0U#wuxmSy|gA4CG&Yl|Gw{sn+Rbpv4f%xttdPJvHLt~n8_k)5REzpG&YiE`)o zj_0|MFrs01NEfqP`q}y<2wuF@MYatW%@eF&zQNQbB}RS432>+9z_z^Ni)qAB7;81` z!qj~OGK&`C^v9}?j-xI+uZAbIjKC*98JxVB)JI5RUi7&)b6S@3ZEvoC>vlL`eW4H8 zMx7T6^GSIZebZ>kkztGpLi^^o>Q}w#&4jrff45}Poaax|*FS#C!RNuVg>cNWjqcps zjbxu6t>ZO2za(J*iyY$IsA-~kL>l7S{P$QUK@?>Q-g=`b`JU&nOU|z;d7G7Qix0QG zlgmN%47HQC3rA;2E@BrXzDyh^{f@eqfBAh}3UgJl8T&z5ySX+IVn=RVsJ?}Onig8{ z=~P@1*Z%k4z&5o{j7Oih&^U8ySa%-KW}I)ITl*n`-eG*9K+lv7Vqo0((<98jlW zHp3Ba()s7bj!kXKcg1$jn=D{Y_rBcM`*OdTGqd*Ed#|(Rn|=1fL8?d)1LuI)3{`cN&jShoAVOh0 z;f9``?mmE_iHXU1lJh+2iE(jq@v!yv#8_j{j%W1#R#`5U+ahAR3O z6)4Xai;IfM2#ZPzi;MlI1oL^;*X17ie{2@JDK0H~0bpogpnATO=6sE|t-qs`w1~Kj zh}ikWe?vGn{O`g45+OYtJoi{?Mf{^9nQ2meU;N8Vpv{-f<5 zLx1`4kF9?Y{&LaEdC&IeJxfVm4E_Tbc<*0$1)<2c9z{6LZ~y@CFNwa_RB®G3NK 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 Cseq^e literal 0 HcmV?d00001 diff --git a/apps/client/public/sounds/standard/Game-End.mp3 b/apps/client/public/sounds/standard/Game-End.mp3 new file mode 100644 index 0000000000000000000000000000000000000000..d5efe4e30147e0cad6b9a8a6999de577db4e6601 GIT binary patch literal 5353 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 CKtRR- literal 0 HcmV?d00001 diff --git a/apps/client/src/hooks/game/useChessGame.ts b/apps/client/src/hooks/game/useChessGame.ts index ad5aa5b..0486f8c 100644 --- a/apps/client/src/hooks/game/useChessGame.ts +++ b/apps/client/src/hooks/game/useChessGame.ts @@ -10,9 +10,10 @@ import type { } from "@chesslab/shared/types"; import { Chess } from "chess.js"; import { useCallback, useEffect, useState } from "react"; -import { useSocket } from "../useSocket"; +import { useSocket } from "@hooks/useSocket"; import type { ChessboardOptions, PieceDropHandlerArgs } from "react-chessboard"; -import useTimer from "./useTimer"; +import useTimer from "@hooks/game/useTimer"; +import { playMoveSound } from "@services/sfx/index"; export function useChessGame(gameId?: string) { const { socket } = useSocket(); @@ -38,6 +39,7 @@ export function useChessGame(gameId?: string) { setChessPosition(fen); setTurn(turn); setTimeInfo(timeInfo); + playMoveSound(chessGame); }, [chessGame], ); diff --git a/apps/client/src/hooks/game/useComputerGame.ts b/apps/client/src/hooks/game/useComputerGame.ts index 453f4b6..4a55c4f 100644 --- a/apps/client/src/hooks/game/useComputerGame.ts +++ b/apps/client/src/hooks/game/useComputerGame.ts @@ -4,13 +4,15 @@ import { Chess } from "chess.js"; import { useState } from "react"; import { getGameOverInfo } from "@chesslab/shared/utils"; import { useCompTimer } from "./useCompTimer"; +import { playMoveSound } from "@services/sfx/index"; export function useComputerGame() { const [chessGame] = useState(() => new Chess()); const [chessPosition, setChessPosition] = useState(() => new Chess().fen()); const [turn, setTurn] = useState<"w" | "b">("w"); const [gameHistory, setGameHistory] = useState([]); - const [side] = useState<"w" | "b">(() => (Math.random() < 0.5 ? "w" : "b")); + // const [side] = useState<"w" | "b">(() => (Math.random() < 0.5 ? "w" : "b")); + const [side] = useState<"w" | "b">(() => "w"); let gameOverInfo = getGameOverInfo(chessGame); @@ -37,6 +39,7 @@ export function useComputerGame() { setChessPosition(chessGame.fen()); setTurn(chessGame.turn()); setGameHistory(chessGame.history()); + playMoveSound(chessGame); }, }); @@ -53,6 +56,8 @@ export function useComputerGame() { if (!move) return false; setChessPosition(chessGame.fen()); + + playMoveSound(chessGame); setTurn(chessGame.turn()); setGameHistory(chessGame.history()); diff --git a/apps/client/src/services/sfx/index.ts b/apps/client/src/services/sfx/index.ts new file mode 100644 index 0000000..5c9a7b5 --- /dev/null +++ b/apps/client/src/services/sfx/index.ts @@ -0,0 +1,46 @@ +import type { Chess } from "chess.js"; + +const sounds = { + move: new Audio("/sounds/standard/Move.mp3"), + check: new Audio("/sounds/standard/Check.mp3"), + capture: new Audio("/sounds/standard/Capture.mp3"), + checkmate: new Audio("/sounds/standard/Game-End.mp3"), + castle: new Audio("/sounds/standard/Castle.mp3"), + promotion: new Audio("/sounds/standard/Promote.mp3"), + defeat: new Audio("/sounds/standard/GenericNotify.mp3"), + draw: new Audio("/sounds/standard/GenericNotify.mp3"), +}; + +function playSound(sound: keyof typeof sounds) { + const audio = sounds[sound]; + + audio.currentTime = 0; + audio.play(); +} + +export function playMoveSound(chess: Chess) { + if (chess.isGameOver()) { + if (chess.isCheckmate()) playSound("checkmate"); + else if (chess.isDraw()) playSound("draw"); + else playSound("defeat"); + return; + } + + const moves = chess.history({ verbose: true }); + if (moves.length > 0) { + const lastMove = moves[moves.length - 1]; + console.log(lastMove); + if (lastMove?.san.endsWith("+")) { + console.log(lastMove.san); + playSound("check"); + } else if (lastMove?.isCapture()) { + playSound("capture"); + } else if (lastMove?.isKingsideCastle() || lastMove?.isQueensideCastle()) { + playSound("castle"); + } else if (lastMove?.isPromotion()) { + playSound("promotion"); + } else { + playSound("move"); + } + } +} diff --git a/apps/client/tsconfig.json b/apps/client/tsconfig.json index 7f2addf..cc5b01b 100644 --- a/apps/client/tsconfig.json +++ b/apps/client/tsconfig.json @@ -21,7 +21,8 @@ "@pages/*": ["./src/pages/*"], "@stockfish/*": ["./src/stockfish/*"], "@app-types/*": ["./src/types/*"], - "@utils/*": ["./src/utils/*"] + "@utils/*": ["./src/utils/*"], + "@services/*": ["./src/services/*"] } }, "include": ["vite.config.ts", "src"] diff --git a/apps/client/vite.config.ts b/apps/client/vite.config.ts index ade004a..a7169db 100644 --- a/apps/client/vite.config.ts +++ b/apps/client/vite.config.ts @@ -20,6 +20,7 @@ export default defineConfig({ "@stockfish": path.resolve(__dirname, "./src/stockfish"), "@app-types": path.resolve(__dirname, "./src/types"), "@utils": path.resolve(__dirname, "./src/utils"), + "@services": path.resolve(__dirname, "./src/services"), }, }, server: { From afcb7fd3b84f6d570222a918eb41ae1720deb1c1 Mon Sep 17 00:00:00 2001 From: Mohamed Date: Sun, 9 Aug 2026 02:04:43 +0300 Subject: [PATCH 2/2] fix: moves don't make sound in multiplayer --- apps/client/src/hooks/game/useChessGame.ts | 2 +- apps/client/src/services/sfx/index.ts | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/apps/client/src/hooks/game/useChessGame.ts b/apps/client/src/hooks/game/useChessGame.ts index 0486f8c..bfb9126 100644 --- a/apps/client/src/hooks/game/useChessGame.ts +++ b/apps/client/src/hooks/game/useChessGame.ts @@ -35,11 +35,11 @@ export function useChessGame(gameId?: string) { const handleMove = useCallback( ({ fen, turn, timeInfo }: MoveMadeEvent) => { + playMoveSound(chessGame); chessGame.load(fen); setChessPosition(fen); setTurn(turn); setTimeInfo(timeInfo); - playMoveSound(chessGame); }, [chessGame], ); diff --git a/apps/client/src/services/sfx/index.ts b/apps/client/src/services/sfx/index.ts index 5c9a7b5..d26aa59 100644 --- a/apps/client/src/services/sfx/index.ts +++ b/apps/client/src/services/sfx/index.ts @@ -29,9 +29,7 @@ export function playMoveSound(chess: Chess) { const moves = chess.history({ verbose: true }); if (moves.length > 0) { const lastMove = moves[moves.length - 1]; - console.log(lastMove); if (lastMove?.san.endsWith("+")) { - console.log(lastMove.san); playSound("check"); } else if (lastMove?.isCapture()) { playSound("capture");