From cd9718ad9299786de5973656290e2ccb5fa10011 Mon Sep 17 00:00:00 2001 From: Maryam Shafiq <108004519+daisy21000@users.noreply.github.com> Date: Thu, 4 Aug 2022 19:27:56 +0100 Subject: [PATCH 01/17] Add option of new neon theme --- index.html | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/index.html b/index.html index 5e955524..166431ec 100755 --- a/index.html +++ b/index.html @@ -60,6 +60,9 @@ case 6: changeTheme('css/head-snake.css?' + Math.random()); break; + case 7: + changeTheme('css/neon-snake.css?' + Math.random()); + break; default: changeTheme('css/main-snake.css?' + Math.random()); break; @@ -94,6 +97,7 @@ +
From 9a9e0a224f6e5e2ea15901ba4ad10905c62a7481 Mon Sep 17 00:00:00 2001 From: Maryam Shafiq <108004519+daisy21000@users.noreply.github.com> Date: Thu, 4 Aug 2022 19:28:57 +0100 Subject: [PATCH 02/17] Add new neon theme stylesheets --- css/neon-snake.css | 139 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 139 insertions(+) create mode 100644 css/neon-snake.css diff --git a/css/neon-snake.css b/css/neon-snake.css new file mode 100644 index 00000000..1be055f0 --- /dev/null +++ b/css/neon-snake.css @@ -0,0 +1,139 @@ +/* +JavaScript Snake +By Patrick Gillespie +http://patorjk.com/games/snake +*/ +body { + margin:0px; + padding:0px; + background-color: #000000; +} + +.snake-toolbar { + color: #ffffff; +} + +#game-area { + margin:10px; + padding:0px; +} + +#mode-wrapper { + color: #ffffff; + font-family: Verdana, arial, helvetica, sans-serif; + font-size: 14px; + +} + +#game-area:focus { outline: none; } + +a.snake-link, a.snake-link:link, a.snake-link:visited { + color: #00FFE0; +} + +a.snake-link:hover { + color: #0FFF00; +} + +.snake-pause-screen { + font-family: Verdana, arial, helvetica, sans-serif; + font-size: 14px; + position:absolute; + width:300px; + height:80px; + text-align:center; + top:50%; + left:50%; + margin-top:-40px; + margin-left:-150px; + display:none; + background-color:#0FFF00; + color:#000000; +} + +.snake-panel-component { + position: absolute; + font-family: Verdana, arial, helvetica, sans-serif; + font-size: 14px; + color: #ffffff; + text-align: center; + padding: 8px; + margin: 0px; +} + +.snake-snakebody-block { + margin: 0px; + padding: 0px; + background-color: #FF0000; + position: absolute; + border: 0px solid #000080; + background-repeat: no-repeat; +} + +.snake-snakebody-alive { + background-image: url('./images/neon-body-snakeblock.png'), url('./css/images/neon-body-snakeblock.png'); +} +.snake-snakebody-dead { + background-image: url('./images/neon-dead-snakeblock.png'), url('./css/images/neon-dead-snakeblock.png'); +} + +.snake-food-block { + margin: 0px; + padding: 0px; + background-color: #FF0000; + border: 0px solid #000080; + position: absolute; +} + +.snake-playing-field { + margin: 0px; + padding: 0px; + position: absolute; + background-color: #00FFD4; + border: 0px solid #0000A8; +} + +.snake-game-container { + margin: 0px; + padding: 0px; + border-width: 0px; + border-style: none; + zoom: 1; + position: relative; +} + +.snake-welcome-dialog { + padding: 8px; + margin: 0px; + background-color: #0FFF00; + color: #000000; + font-family: Verdana, arial, helvetica, sans-serif; + font-size: 14px; + position: absolute; + top: 50%; + left: 50%; + width: 300px; + /*height: 150px;*/ + margin-top: -100px; + margin-left: -158px; + text-align: center; + display: block; +} + +.snake-try-again-dialog, .snake-win-dialog { + padding: 8px; + margin: 0px; + background-color: #0FFF00; + color: #000000; + font-family: Verdana, arial, helvetica, sans-serif; + font-size: 14px; + position: absolute; + top: 50%; + left: 50%; + width: 300px; + height: 100px; + margin-top: -75px; + margin-left: -158px; + text-align: center; + display: none; +} From 8bd63208d1629c0b1775df2029b4f4b725b5e166 Mon Sep 17 00:00:00 2001 From: Maryam Shafiq <108004519+daisy21000@users.noreply.github.com> Date: Thu, 4 Aug 2022 19:29:48 +0100 Subject: [PATCH 03/17] Add new neon theme snakeblocks --- css/images/neon-body-snakeblock.png | Bin 0 -> 5213 bytes css/images/neon-dead-snakeblock.png | Bin 0 -> 5198 bytes 2 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 css/images/neon-body-snakeblock.png create mode 100644 css/images/neon-dead-snakeblock.png diff --git a/css/images/neon-body-snakeblock.png b/css/images/neon-body-snakeblock.png new file mode 100644 index 0000000000000000000000000000000000000000..1a7107d36117193e69c9a0e6b0b0d308ab1d4bff GIT binary patch literal 5213 zcmeHKc~n#95)Xoa5vUfbpg}{VAY%4}kO*Q;Sn?$72#P2-H#Z@W%_JBWE6Acy6xk}3 zihwLdrHDmE1YAG`MT%k-MFBPElHrC8eF(&EFBZWdgYSu(eE3IxLFg8I<<(bi}o0x@%Dv|pgo2T;8$5?UE0gV0c< zkdHt_b`AuJGoLRtnrO3msjqJ_r|AKiD{aDcWzWQ*VZJJ-?&*=|hU22NRW+rq>XCs?YcO#GNF&JukLS7HDk} zRF}0?o^=pZ(sV{-`dKNCgWDf!#SJV(1^9*bC@OOcen+WV8cp@1E@n+8Ug`3$2^-~% zb4)y3YnhGYef`Teoy@w|>6sw$oe=T|JFa>TKnJ`dmfSfLZWs~X+E}~5cq!)>-}x)n zoNalB z3aE6}GA-TTMMTD5i@uN{ieKFE20Y#AVevCRDdA>yBg>cpw)7@fU)!}k{zYJTc9Rfc z0!Xw>xl8XG$LD|j8nxPL#vbJN%M5JhaYEDMSPh6PbM_fuxE`W-nCBiNN|#Z zDdb|C4Tb&}F6|h*>^+z1A9yg?^728SVk-|K`(HNJcPGLgqpBWdD{gI&``;=%$gVnk z^^&K4BM&zu9ZsU191KK6`hNsNJW96C^ybWNY;EcHg$(V0?WVAu=T2 zRQRZ{Xct3>$>#4T-MH#2*cV~($GoGbcqKpPRQ&d|WI+w{7QUm+zi4L|U<+xFlq}fT z`WlEAt(bem;D;nPFNdFJ=syX`jVdusAoshIH_cd^q*GvGEJ(M}o%ygBor)V+nH|&K zdT}i1bka`w@5STBSLj)T3;WJIeYyGsa5wnX^OLJj8tnFK3*1I1poRvogcy=;NzzOK3*HOP3Zs0d2`@)Fd^g#YHfZ^`MNAFGB=@2 zW}<(pwkvvckv?%k>zHSs_uRVv#_iJKD%-|?`Wns4`YQutUOB zsh%&c=(<*)`1bM%!C-7&w5oBE{M7N5S%X1=PiAt@x^n8-hs*mcZpT-;H@dqWO2oX4 zexrXQW5LfraB{_g05chhYIA>CM|#(zo7T&ABdu=9%d5I;d#nym0{s(vHhBe&XB9TQ zC|HF|P!hH~FgxNcT2pOLnQH|>jr@a6M-17$tyS~4ZFe3KopyR;ws!Jp1f8Fy+T1Rw z*^)`l+1>KCs>;VnE=Ij*wwg_yk4hCR=3Rd2dUOfO#D%Wt->!{G?Q8ktn|{LAn~OVZ z?~;bQcC%`e^4tPY%YCc1?wg(V%xqC$ZhZ{au;)#5{EEVLXBI2;oBOiPum%UOMYveL z$j`V-1XLr2ca4=Q;OvG}mGZ06w)@g+T{DNM|5^BK{%QRE{0-ygon5NtSeM#7$(5C? zTFcA<6Y=CPTUj}7>51A#9JA5hxRJxkv$4ICuFSxJaFbU~j^~Kmo9-P6f!}7PLUV%90fe^t<@PG7jfGyhJh0 z0?Y?K5|H7EI09ZQ#(!*~P&#jcL8b%xTMLCB{9eKPKniJu9E6;=KoaGWk0E&AdwW@g zT%<{d2jU?SB!*QLuvg+IE?wCiulE*e3Isy2Ok)L;{fVYh$p1jrC$Xs|nsh!61U7$< z`-%3u+%?Lu7Kg)NNx=wpcx;vrH35`_|wfRGvr2FD3u90Hw22KhV?%LD0jEX9sT!~zte9hOhBr;s3f zE(w6BA3=D^g>Y8_qK~6eL-AlJJ1&(75=k^HK;V;LC^{9(rP6p<0-X#}2sD~KodRi~ zcp$??Di;HAIfY_C0O4g4fkvPvobjC(+Yv*;5k9PVi2x-ZHh}klP{Na{6dy!>LNVm4 z1k`*I?I=X5ogINfCKD($%2d=E#I=xI0r#RBl}NymC>nEhVHj{aFtvcXQ(*wjI-CuI zDTe^1RPHC0iX1U&2(;Q#)8J@_sj|2U6|hE>y6306-WS?D^)$5!L_&=Sjn*_S0|2L- zD1a>xPvZ!-n-YPcfJ6YnJAAsO-mMG&rd%|83IsuX3Kk%7K`ezpCt>YrkR6r_5~wu3 zogEjVaz8~^Ncr#>lSAJL;7s9c;1<$kgI+pKrp>4Ns!&MH6an7f1R|C|^CMCjWD0{o z#^9%u#jE%9yKEis|HFraM&Y9&0NYKi!NUcfRrvSAYML)Kh5z7hx(@%K2N?Q`lh5M! z3teC6`YZ-MOZiK8eWB~K82BvZFWvQjqYL@ra|e>Z|A18R$4rIc*RJq~ke-swan^gR zrDufE{wXM`6kejSS>O5DdxE^N$w?>eZ?ufFOBck|{^^v?o`qPTQ+jBy!CTu#uSnO& m$i=W2Ww1?KFD9k+90K8%Iomu$i4egM2)45at73IX{C@#am;HqR literal 0 HcmV?d00001 diff --git a/css/images/neon-dead-snakeblock.png b/css/images/neon-dead-snakeblock.png new file mode 100644 index 0000000000000000000000000000000000000000..55da41ab4a51d49002cbc6f44f3a182b0eceb161 GIT binary patch literal 5198 zcmeHKc~n#95)ZP75l{DL)db%>1D2Y_e6NEts#PYVE(ikpv zo<>O?K1FE1nWSB|+!FWsEJu^?esnDN>_q-X|M}eToNThW6*ff~T3efY`Dj9NMVUdF z5;dy%_}SCKXXx*`vy3(-A~#2#+c(rryRTS^y4m7ZS#5#nl9Y1Y_7m^=Sq=Y)So3VB zt}AeQp$De;`ib)ceKxlOGx?9=ZvEO5rlV#4n8w>^@Ji>^)nZWEZ8?8~*Y#a(yBjbe zsiSExj<$&p&R#Ox&gW!%Qxqr7f5piYomWbO`|5Ah&tp@UZ)qGY-P--QH0xODUCTJY zmS0+U#ywPvu+l6=%eua1nl8}r{hF+23b@cn_Zln|-fiC-OA5 z@GDE&$}iaQ%c)vJ65Wj5jDh$k8r%C9o2>T@ejqE)&ilhe(Nbru8+AEjBC)y4uPS7i zJ;pY2cdlmEkq-2&*m64Key2x*$Y)%@8|b*|(GMN+3SV~je5ihSXlq^dBE#kEUwsy= zT335fr#b4vehCz-{nxqU%C)AweW|gd1B=VtlV)%?7zsR!9A#NKbkr5Rrui(h;fvL5 zGp|`WH3{z5u^Y`~k7|*GRZl5Bmy(i3&Osg>u7p>pJ$hQ8ym9IKtAG8Le`@8^-RCxM z(pX>as9{`uu#13HUW=|z3sWxbcn6;CbT|8jmy~d;vW{g)2U{NRs=T%*UisQTG_yf~ zFaksx#+>C34VAgyyfs;4F=HR{hZTBO^Vz|v+gXaXk=ZStDO^z%Qw%e?8ZccFzl!S!EOmiNX(dQB>xX3B1FlKR~)IqX_- z^v2;+iI?t}6cwf?@AnS5T=?yN>+UjR&(PU>1H#(9Ti5}DQ_EtbU$*6gK^YZkX(|UV-+x)lT^C-cA_MDTIE4JN# ze?;zJIvToT$4vb^>S?`VaA&E6h@G2iVSA)KKzMb#eR~MGQ+ljUoXWJ`+7f!#CU-%J zzZVV%$g0ojLwp3fTL6y|?FPO(WWWvfdrK6NnFbX0k4~s&qpJ2brBv zA~DiEQ{5FkyhN8Uu5rSn$7|lXzPfnvs|xG7f8$1TuRG+&Xg|0w>wS>)ey}`F+P_1@ zR4869E$g~gllZ>r6n`KtCt6WAL3+-(z3`G=o_G4L2OCN$7oM!_F}tHIcdK)AIg*He zAN@}EM%toZfWTd4ht@BY5GhsJ&(f^G4RLt$qfo-SNBaXhj&_lLUU z^>WGJ#Gn1Ybq1WO3=!YzK3d}!b8KW?{}!LtKWLC;o-M#zyPEIzzR|&I{`!F0S&FUg zqN<2=Qr6y<_Z1c14pO1X>qd*&lm#Zq{H5Hc5$EH}OpKgpvc7mtbaGG2&2Rhg-)t@H ztiDHl)wP#Zos{FU-ejduMeKpuDK8c-@z1V_!RSAD7p+{Czv28+nQmiG#(CDjz_oBE z^Vhj)_XvPuNdKOpTmf9zl&p}?8E$(hzSgBZNcqp=7Yokf9_DTuGwtkBG{!kq=ZKo^ zS=Hw0{YJuxUt?KWE~$x{2JD5ykGBsUm0yT^JmJjr?+-P46(p=!%Eu9CG#U<1 z#1V-YSOX)A63Kx`j7YXj1u==if@GjnAdw5iB9saf;E2QJ3^W>+qdvqZl(5+!;YG43 z7GOSbk$?n8z~XU2A#S>bOzs!~gG>eVw-z#A_`QPjhGgP!DF``6KqC3F=@4A-qrD_t z8m3N%3*w+KNC>OSV6TMFTsph5JwIBgDBuf(615df_Gg-M0q+x8pT(w3>T!)Fk~Ap0RxZ;HW(h!mP~|f zIYa=WOoQ-{3gE5;!lp;1g5ttZHXI58BoL_>0M8@BP&5jLL!ojpcp3>LJDIQ@H1R|cAh#eZ7y3u@%7 zrW69?VyUlK9L7MaAW$kxb%UeqCd=X?kii;Js-BRzC zL{SO~@YK3V-0JfW4gNF+|t8gEO)f8VU3je{+R2}|74>0ssCtt+x zSGvB^^+gPPk@DB>`byUqG4MsoU%Tu7Mi=taaR(B?|9}+mVWv#~8)x_+G*j-%cAVL( zG1CC8`Ex*2F}$?gmG!-^tp~^*os;OR<>r|k5_EHQb8Sg{W`dWd)yx7NZv&m`cs)JD XV(l3gF?AuDssoj)qdTi?O_1`xXa4u? literal 0 HcmV?d00001 From 12b320ed373ae18db238d02fc47b8e9a35d4c83f Mon Sep 17 00:00:00 2001 From: Maryam Shafiq <108004519+daisy21000@users.noreply.github.com> Date: Thu, 4 Aug 2022 20:30:27 +0100 Subject: [PATCH 04/17] Delete neon snake-alive body for changes --- css/images/neon-body-snakeblock.png | Bin 5213 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 css/images/neon-body-snakeblock.png diff --git a/css/images/neon-body-snakeblock.png b/css/images/neon-body-snakeblock.png deleted file mode 100644 index 1a7107d36117193e69c9a0e6b0b0d308ab1d4bff..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5213 zcmeHKc~n#95)Xoa5vUfbpg}{VAY%4}kO*Q;Sn?$72#P2-H#Z@W%_JBWE6Acy6xk}3 zihwLdrHDmE1YAG`MT%k-MFBPElHrC8eF(&EFBZWdgYSu(eE3IxLFg8I<<(bi}o0x@%Dv|pgo2T;8$5?UE0gV0c< zkdHt_b`AuJGoLRtnrO3msjqJ_r|AKiD{aDcWzWQ*VZJJ-?&*=|hU22NRW+rq>XCs?YcO#GNF&JukLS7HDk} zRF}0?o^=pZ(sV{-`dKNCgWDf!#SJV(1^9*bC@OOcen+WV8cp@1E@n+8Ug`3$2^-~% zb4)y3YnhGYef`Teoy@w|>6sw$oe=T|JFa>TKnJ`dmfSfLZWs~X+E}~5cq!)>-}x)n zoNalB z3aE6}GA-TTMMTD5i@uN{ieKFE20Y#AVevCRDdA>yBg>cpw)7@fU)!}k{zYJTc9Rfc z0!Xw>xl8XG$LD|j8nxPL#vbJN%M5JhaYEDMSPh6PbM_fuxE`W-nCBiNN|#Z zDdb|C4Tb&}F6|h*>^+z1A9yg?^728SVk-|K`(HNJcPGLgqpBWdD{gI&``;=%$gVnk z^^&K4BM&zu9ZsU191KK6`hNsNJW96C^ybWNY;EcHg$(V0?WVAu=T2 zRQRZ{Xct3>$>#4T-MH#2*cV~($GoGbcqKpPRQ&d|WI+w{7QUm+zi4L|U<+xFlq}fT z`WlEAt(bem;D;nPFNdFJ=syX`jVdusAoshIH_cd^q*GvGEJ(M}o%ygBor)V+nH|&K zdT}i1bka`w@5STBSLj)T3;WJIeYyGsa5wnX^OLJj8tnFK3*1I1poRvogcy=;NzzOK3*HOP3Zs0d2`@)Fd^g#YHfZ^`MNAFGB=@2 zW}<(pwkvvckv?%k>zHSs_uRVv#_iJKD%-|?`Wns4`YQutUOB zsh%&c=(<*)`1bM%!C-7&w5oBE{M7N5S%X1=PiAt@x^n8-hs*mcZpT-;H@dqWO2oX4 zexrXQW5LfraB{_g05chhYIA>CM|#(zo7T&ABdu=9%d5I;d#nym0{s(vHhBe&XB9TQ zC|HF|P!hH~FgxNcT2pOLnQH|>jr@a6M-17$tyS~4ZFe3KopyR;ws!Jp1f8Fy+T1Rw z*^)`l+1>KCs>;VnE=Ij*wwg_yk4hCR=3Rd2dUOfO#D%Wt->!{G?Q8ktn|{LAn~OVZ z?~;bQcC%`e^4tPY%YCc1?wg(V%xqC$ZhZ{au;)#5{EEVLXBI2;oBOiPum%UOMYveL z$j`V-1XLr2ca4=Q;OvG}mGZ06w)@g+T{DNM|5^BK{%QRE{0-ygon5NtSeM#7$(5C? zTFcA<6Y=CPTUj}7>51A#9JA5hxRJxkv$4ICuFSxJaFbU~j^~Kmo9-P6f!}7PLUV%90fe^t<@PG7jfGyhJh0 z0?Y?K5|H7EI09ZQ#(!*~P&#jcL8b%xTMLCB{9eKPKniJu9E6;=KoaGWk0E&AdwW@g zT%<{d2jU?SB!*QLuvg+IE?wCiulE*e3Isy2Ok)L;{fVYh$p1jrC$Xs|nsh!61U7$< z`-%3u+%?Lu7Kg)NNx=wpcx;vrH35`_|wfRGvr2FD3u90Hw22KhV?%LD0jEX9sT!~zte9hOhBr;s3f zE(w6BA3=D^g>Y8_qK~6eL-AlJJ1&(75=k^HK;V;LC^{9(rP6p<0-X#}2sD~KodRi~ zcp$??Di;HAIfY_C0O4g4fkvPvobjC(+Yv*;5k9PVi2x-ZHh}klP{Na{6dy!>LNVm4 z1k`*I?I=X5ogINfCKD($%2d=E#I=xI0r#RBl}NymC>nEhVHj{aFtvcXQ(*wjI-CuI zDTe^1RPHC0iX1U&2(;Q#)8J@_sj|2U6|hE>y6306-WS?D^)$5!L_&=Sjn*_S0|2L- zD1a>xPvZ!-n-YPcfJ6YnJAAsO-mMG&rd%|83IsuX3Kk%7K`ezpCt>YrkR6r_5~wu3 zogEjVaz8~^Ncr#>lSAJL;7s9c;1<$kgI+pKrp>4Ns!&MH6an7f1R|C|^CMCjWD0{o z#^9%u#jE%9yKEis|HFraM&Y9&0NYKi!NUcfRrvSAYML)Kh5z7hx(@%K2N?Q`lh5M! z3teC6`YZ-MOZiK8eWB~K82BvZFWvQjqYL@ra|e>Z|A18R$4rIc*RJq~ke-swan^gR zrDufE{wXM`6kejSS>O5DdxE^N$w?>eZ?ufFOBck|{^^v?o`qPTQ+jBy!CTu#uSnO& m$i=W2Ww1?KFD9k+90K8%Iomu$i4egM2)45at73IX{C@#am;HqR From b1fa26bcdaa9fe5c6ec4d3d7fc081429608bbfb0 Mon Sep 17 00:00:00 2001 From: Maryam Shafiq <108004519+daisy21000@users.noreply.github.com> Date: Thu, 4 Aug 2022 20:31:20 +0100 Subject: [PATCH 05/17] Add new edited neon snake-alive body --- css/images/neon-body-snakeblock.png | Bin 0 -> 5200 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 css/images/neon-body-snakeblock.png diff --git a/css/images/neon-body-snakeblock.png b/css/images/neon-body-snakeblock.png new file mode 100644 index 0000000000000000000000000000000000000000..d66f77173bc74d9377bc9adda5259ff59cd8b421 GIT binary patch literal 5200 zcmeHKc~n#95)YeV6sm2m_WI(;NOZR$uzl;P2f#%?uC-twbS%;mKk!P*RzMFARqeh~+Imr8~IQ zdKxEr_!OZ1rjwHGctxDKOlQ-jKRTCswj+O||6DclO%B<@3Y)45tEtJoax5XGti-TH zg&Ng){In8^8E6h`MEsBZ`ClXDWLaN)z^n7_mLfqZqW%UIa$8}v&^?dUfL*ozQ{){=Z zWou}w2eN6^>y+nPcWECA%JY(U41#T<{fHXD!^V&|HW9(EGDp_0Nio&ZxqtCW#2TO1 z+nUURpEmfexRR+ll^DAy(&>n#Q9Gf0)nJZO`4bvv@iuaE=$mPFcDh%QS=F77Ivo1t zW5cObr+O#Xm$JP@%A8ENEHk8T>*NT8;brxu^^=X^LIgrjFWNUi;SDI?7YU_^l0qmb zQpiUjBHQ}|L>VuZ8;-YFz0%h=pI!He#FgOdx{S9}R6e*(svfLPe&f@NP0&j5EzDz9 zzG;ig9{a}e#Sx{~?}Zr|b<6e!taf&OJ9Ko6V=(D{(H^%QJ+3tB6JCUcg zNl;$YQhLE&P)gMumg;BjbQp;5*4oy;(A3{Iq)T3!llOZYKk7>6L}FuyUq$E$ zdyH+&ajj(3lJ@mkZ#t9tpxq-u>@zOp542tL=!Xt^MJ%~@KFlB@thu&wfzfjIuRilu zuC2K^tugAtUMUo-_gB>k)f%%WeQB|y0}D$yN!q-1#zM~mXLR;o${tGZrKF@+Rggy;i!g-RHA@#%)GvN_?XTYsonFzivufi8 zE&ozyEtA6i9R#H6di3S=aMj|rx8S*Uj`=VAq=eh$wM-*A*z`EL{Q9nV)ysgetU4jW z7!YfjaF;(cQssX8#&or%_8#O9*0ZeUvP06gF)tw+XYVt*d?Q%ieZV~?JWWalTU4_z z?Ih(}Z8+q2`Rex32Cq2`zktKZ77d5J^DQ|9*1xQl-5(EqVp`UdCBL&l=69#)Fstm? z&BLb?FWogQ$j?aG>m7O}|GT|5oh2roVKa9JhPQe*u>*ytm&8WDX!U6c3c^*V;v<7| zO@uv%j_jff(OLZc#GBWA1p6Y)Z_Pb%mRImocFFJ03Kmo_?%>*5{EqAh1#BRl;erJl zo8JJc@Rf6J&iXOQ&C~uDZT+XgIZ*{B38X%E(kAV-NxFH)MuIe}X?orHs1$6!V^&OS z^Oe!Sb4fd7f8>uDHPSK%7WSTh_G!e4o*PN=p+IY!OnN97#aih66oDRk4bv=+j=}LMxSQ;nm-!5h- zl`j^TbX>1aeAjSVFc5bjT3I_mdggFv{-s%Y-WkbV>xwBCx>xj?-&K{m*SfnMO+>$o zeye{oeZen4P;$vZ|M^lP#p+)@G7nvP znYRj=puor5Gul+<%_%l#&9nlcTK?g>;|8q9&1Lhp#yby(pL6P&zjoq8~-8VD!`TRuzIn^;3gRZyHs+EVaW0hy#Ep*3 zN{ftsW6{K~vCM3@v_u_4_WY5@+lG%RF2p^aaAgGahZ(sD5)l^QNw^R;QY3}PCjw#b6e$J3Fi3&oLIR=K0X-?PxofJOhLd;4(JetLQ2Qslu9L5Ny18G0vv%xqv7yG z9Fd5DH8Aohu>y$1h~-Pv5R({8NDj(`QiV_=MyW9Yt|UU?fJVb|)cg2EQa1YoyjVWP z0?Y?45|H8uSUgT7!hLEXS2%BhL8b!wTMM}_{9eI%Lvl%k41}DwKw`y`Pa$~V2YYFR zEL@Wg55z&?kO)?l!(IuWxpZZ*JwI5eDG&%nQjHZ%_Gg+3A^#&;pT(w@XwvyK5ZL?! z?q}NXbJr-tT5L9*DFGwY;jx$wXtjSjPXY>gbj>Z*mTODp5&0Mb70<KYVaT>T0tO%xY%zSI9hnH( zaftv#`2@m4CWN~Z2>&!HH53nqvgJ|;Ac0850C+wThN4k0Tnd$k!P7_}8Be9!(a4Yn ziU-nNBr*{Ims2PL1Q1Rt7H9-&!s*|8vK-JvEdJw)XE>nX!v^pk5Q=#crTnAFS15vf z6o8sff-RXqv9-mMNhCa(N}h~bgSZxw$>Cm9qZ05~B3WauE({$`2c{NKcPb2^S%P*|`hB+cxc}k9UZe2I5P--!TRR}LxvzXue+IfKE6S2I!kdgyR_9uDwZ>cS+Y7<^ Date: Thu, 18 Jan 2024 13:51:13 -0300 Subject: [PATCH 06/17] new style added --- css/black-snake.css | 136 ++++++++++++++++++++++++++++++++++++++++++++ index.html | 6 +- 2 files changed, 141 insertions(+), 1 deletion(-) create mode 100644 css/black-snake.css diff --git a/css/black-snake.css b/css/black-snake.css new file mode 100644 index 00000000..0c460b7c --- /dev/null +++ b/css/black-snake.css @@ -0,0 +1,136 @@ +/* +JavaScript Snake +By Patrick Gillespie +http://patorjk.com/games/snake +*/ +body { + margin:0px; + padding:0px; + background-color: black; + color: white; +} + +#game-area { + margin:10px; + padding:0px; +} + +#mode-wrapper { + color: #ffffff; + font-family: Verdana, arial, helvetica, sans-serif; + font-size: 14px; + +} + +#game-area:focus { outline: none; } + +a.snake-link, a.snake-link:link, a.snake-link:visited { + color: #FCFC54; +} + +a.snake-link:hover { + color: #FfFf54; +} + +.snake-pause-screen { + font-family: Verdana, arial, helvetica, sans-serif; + font-size: 14px; + position:absolute; + width:300px; + height:80px; + text-align:center; + top:50%; + left:50%; + margin-top:-40px; + margin-left:-150px; + display:none; + background-color:black; + color:white; +} + +.snake-panel-component { + position: absolute; + font-family: Verdana, arial, helvetica, sans-serif; + font-size: 14px; + color: #ffffff; + text-align: center; + padding: 8px; + margin: 0px; +} + +.snake-snakebody-block { + margin: 0px; + padding: 0px; + background-color: #FF0000; + position: absolute; + border: 0px solid #000080; + background-repeat: no-repeat; +} + +.snake-snakebody-alive { + background-image: url('./css/images/snakeblock.png'), url('./images/snakeblock.png'); +} +.snake-snakebody-dead { + background-image: url('./css/images/deadblock.png'), url('./images/deadblock.png'); +} + +.snake-food-block { + margin: 0px; + padding: 0px; + background-color: aqua; + border: 0px solid #000080; + position: absolute; +} + +.snake-playing-field { + margin: 0px; + padding: 0px; + position: absolute; + background-color: purple; + border: 0px solid purple; +} + +.snake-game-container { + margin: 0px; + padding: 0px; + border-width: 0px; + border-style: none; + zoom: 1; + position: relative; +} + +.snake-welcome-dialog { + padding: 8px; + margin: 0px; + background-color: #000000; + color: #ffffff; + font-family: Verdana, arial, helvetica, sans-serif; + font-size: 14px; + position: absolute; + top: 50%; + left: 50%; + width: 300px; + /*height: 150px;*/ + margin-top: -100px; + margin-left: -158px; + text-align: center; + display: block; +} + +.snake-try-again-dialog, .snake-win-dialog { + padding: 8px; + margin: 0px; + background-color: #000000; + color: #ffffff; + font-family: Verdana, arial, helvetica, sans-serif; + font-size: 14px; + position: absolute; + top: 50%; + left: 50%; + width: 300px; + height: 100px; + margin-top: -75px; + margin-left: -158px; + text-align: center; + display: none; +} diff --git a/index.html b/index.html index 5e955524..77442c73 100755 --- a/index.html +++ b/index.html @@ -57,9 +57,12 @@ case 5: changeTheme('css/Senura-snake.css?' + Math.random()); break; - case 6: + case 6: changeTheme('css/head-snake.css?' + Math.random()); break; + case 7: + changeTheme("css/black-snake.css?" + Math.random()); + break; default: changeTheme('css/main-snake.css?' + Math.random()); break; @@ -94,6 +97,7 @@ +
From 3de7b6ae0d44bceeea94a188f879a46fd31eee19 Mon Sep 17 00:00:00 2001 From: mmpalasc <114777311+mmpalasc@users.noreply.github.com> Date: Mon, 19 Feb 2024 01:33:30 +0200 Subject: [PATCH 07/17] Pause and info Added pause when window minimized or user changes tab. Added game info button in welcome screen. --- js/snake.js | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/js/snake.js b/js/snake.js index 556637f7..91ccf984 100644 --- a/js/snake.js +++ b/js/snake.js @@ -669,6 +669,7 @@ SNAKE.Board = SNAKE.Board || (function() { mySnake, boardState = 1, // 0: in active; 1: awaiting game start; 2: playing game myKeyListener, + myWindowListener, isPaused = false,//note: both the board and the snake can be paused // Board components elmContainer, elmPlayingField, elmAboutPanel, elmLengthPanel, elmHighscorePanel, elmWelcome, elmTryAgain, elmWin, elmPauseScreen; @@ -754,6 +755,13 @@ SNAKE.Board = SNAKE.Board || (function() { welcomeTxt.innerHTML = "JavaScript Snake

Use the arrow keys on your keyboard to play the game. " + fullScreenText + "

"; var welcomeStart = document.createElement("button"); welcomeStart.appendChild(document.createTextNode("Play Game")); + + //Game info + var gameinfo = document.createElement("button"); + gameinfo.appendChild(document.createTextNode("Info")); + var gameInfo = function() { + alert("Welcome to Snake! The goal of the game is to eat the food. Each time you eat food, you grow longer. You die if you run into the wall or yourself. Good luck!"); + } var loadGame = function() { SNAKE.removeEventListener(window, "keyup", kbShortcut, false); tmpElm.style.display = "none"; @@ -768,11 +776,14 @@ SNAKE.Board = SNAKE.Board || (function() { loadGame(); } }; + SNAKE.addEventListener(window, "keyup", kbShortcut, false); SNAKE.addEventListener(welcomeStart, "click", loadGame, false); + SNAKE.addEventListener(gameinfo, "click", gameInfo, false); tmpElm.appendChild(welcomeTxt); tmpElm.appendChild(welcomeStart); + tmpElm.appendChild(gameinfo); return tmpElm; } @@ -849,6 +860,7 @@ SNAKE.Board = SNAKE.Board || (function() { */ me.resetBoard = function() { SNAKE.removeEventListener(elmContainer, "keydown", myKeyListener, false); + SNAKE.removeEventListener(elmContainer, "visibilitychange", myWindowListener, false); mySnake.reset(); elmLengthPanel.innerHTML = "Length: 1"; me.setupPlayingField(); @@ -1005,6 +1017,7 @@ SNAKE.Board = SNAKE.Board || (function() { // This removes the listener added at the #listenerX line SNAKE.removeEventListener(elmContainer, "keydown", myKeyListener, false); + SNAKE.removeEventListener(elmContainer, "visibilitychange", myWindowListener, false); myKeyListener = function(evt) { if (!evt) var evt = window.event; @@ -1023,7 +1036,17 @@ SNAKE.Board = SNAKE.Board || (function() { if (evt.preventDefault) {evt.preventDefault();} return false; }; + + //listener for pausing the game if user change tab or minimize the browser window + document.addEventListener("visibilitychange", () => { + if (document.visibilityState === 'hidden') { + if(me.getBoardState()!=0 && !me.getPaused()) + me.setPaused(true); + } + }); + SNAKE.addEventListener( elmContainer, "keydown", myKeyListener, false); + SNAKE.addEventListener( elmContainer, "visibilitychange", myWindowListener, false); mySnake.rebirth(); mySnake.handleArrowKeys(keyNum); @@ -1039,6 +1062,7 @@ SNAKE.Board = SNAKE.Board || (function() { // Search for #listenerX to see where this is removed SNAKE.addEventListener( elmContainer, "keydown", myKeyListener, false); + SNAKE.addEventListener( elmContainer, "visibilitychange", myWindowListener, false); }; /** From b15c66d442d12606cd411857ea0da3488e4c1dcc Mon Sep 17 00:00:00 2001 From: patorjk Date: Wed, 29 Jan 2025 22:36:25 -0500 Subject: [PATCH 08/17] Updated to work with Parcel 2 --- .gitignore | 1 + .parcelrc | 4 + README.md | 10 + package-lock.json | 3389 +++++++++++++++++ package.json | 13 +- {css => src/css}/Senura-snake.css | 4 +- {css => src/css}/black-snake.css | 4 +- {css => src/css}/dark-snake.css | 4 +- {css => src/css}/green-snake.css | 4 +- {css => src/css}/head-snake.css | 6 +- {css => src/css}/images/Thumbs.db | Bin {css => src/css}/images/dark-snakeblock.png | Bin .../css}/images/dead-dark-snakeblock.png | Bin {css => src/css}/images/deadblock.png | Bin {css => src/css}/images/deadblock_border.png | Bin {css => src/css}/images/favicon.png | Bin .../css}/images/green-body-snakeblock.png | Bin .../css}/images/green-head-snakeblock.png | Bin {css => src/css}/images/matrix-food-block.png | Bin .../css}/images/matrix-snake-block.png | Bin .../css}/images/neon-body-snakeblock.png | Bin .../css}/images/neon-dead-snakeblock.png | Bin {css => src/css}/images/snakeblock.png | Bin {css => src/css}/light-snake.css | 4 +- {css => src/css}/main-snake.css | 4 +- {css => src/css}/matrix-snake.css | 8 +- {css => src/css}/neon-snake.css | 4 +- {css => src/css}/teal-snake.css | 4 +- index.html => src/index.html | 30 +- {js => src/js}/init.js | 0 {js => src/js}/snake.js | 41 +- 31 files changed, 3466 insertions(+), 68 deletions(-) create mode 100644 .gitignore create mode 100644 .parcelrc create mode 100644 package-lock.json rename {css => src/css}/Senura-snake.css (94%) rename {css => src/css}/black-snake.css (92%) rename {css => src/css}/dark-snake.css (94%) rename {css => src/css}/green-snake.css (95%) rename {css => src/css}/head-snake.css (90%) rename {css => src/css}/images/Thumbs.db (100%) rename {css => src/css}/images/dark-snakeblock.png (100%) rename {css => src/css}/images/dead-dark-snakeblock.png (100%) rename {css => src/css}/images/deadblock.png (100%) rename {css => src/css}/images/deadblock_border.png (100%) rename {css => src/css}/images/favicon.png (100%) rename {css => src/css}/images/green-body-snakeblock.png (100%) rename {css => src/css}/images/green-head-snakeblock.png (100%) rename {css => src/css}/images/matrix-food-block.png (100%) rename {css => src/css}/images/matrix-snake-block.png (100%) rename {css => src/css}/images/neon-body-snakeblock.png (100%) rename {css => src/css}/images/neon-dead-snakeblock.png (100%) rename {css => src/css}/images/snakeblock.png (100%) rename {css => src/css}/light-snake.css (95%) rename {css => src/css}/main-snake.css (93%) rename {css => src/css}/matrix-snake.css (92%) rename {css => src/css}/neon-snake.css (86%) rename {css => src/css}/teal-snake.css (95%) rename index.html => src/index.html (89%) rename {js => src/js}/init.js (100%) rename {js => src/js}/snake.js (98%) diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..f78ec928 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +.parcel-cache diff --git a/.parcelrc b/.parcelrc new file mode 100644 index 00000000..1f3df894 --- /dev/null +++ b/.parcelrc @@ -0,0 +1,4 @@ +{ + "extends": ["@parcel/config-default"], + "reporters": ["...", "parcel-reporter-static-files-copy"] +} diff --git a/README.md b/README.md index 7f373fc1..fff1ef7a 100755 --- a/README.md +++ b/README.md @@ -27,6 +27,16 @@ The index.html file should give an idea of how to use this code. However, below The comments within the source code are formatted a little strange because at the time I was playing around with YUI Doc which generates documentation from code. Kind of sucks that there's so much churn in the JavaScript world. However, I'm glad the rest of the code doesn't use any external libraries, as this game still works the same after over a decade. +## Running + +Clone project, then at command line: + +``` +npx parcel src/index.html +``` + +Runs on http://localhost:1234 + ## Contributors Thanks goes to these people: ([emoji key](https://allcontributors.org/docs/en/emoji-key)) diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 00000000..d7f43490 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,3389 @@ +{ + "name": "javascript-snake", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "javascript-snake", + "version": "1.0.0", + "license": "MIT", + "devDependencies": { + "parcel": "^2.13.3", + "parcel-reporter-static-files-copy": "^1.5.3" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.26.2", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.26.2.tgz", + "integrity": "sha512-RJlIHRueQgwWitWgF8OdFYGZX328Ax5BCemNGlqHfplnRT9ESi8JkFlvaVYbS+UubVY6dpv87Fs2u5M29iNFVQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-validator-identifier": "^7.25.9", + "js-tokens": "^4.0.0", + "picocolors": "^1.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.25.9.tgz", + "integrity": "sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@lezer/common": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@lezer/common/-/common-1.2.3.tgz", + "integrity": "sha512-w7ojc8ejBqr2REPsWxJjrMFsA/ysDCFICn8zEOR9mrqzOu2amhITYuLD8ag6XZf0CFXDrhKqw7+tW8cX66NaDA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@lezer/lr": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/@lezer/lr/-/lr-1.4.2.tgz", + "integrity": "sha512-pu0K1jCIdnQ12aWNaAVU5bzi7Bd1w54J3ECgANPmYLtQKP0HBj2cE/5coBD66MT10xbtIuUr7tg0Shbsvk0mDA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@lezer/common": "^1.0.0" + } + }, + "node_modules/@lmdb/lmdb-darwin-arm64": { + "version": "2.8.5", + "resolved": "https://registry.npmjs.org/@lmdb/lmdb-darwin-arm64/-/lmdb-darwin-arm64-2.8.5.tgz", + "integrity": "sha512-KPDeVScZgA1oq0CiPBcOa3kHIqU+pTOwRFDIhxvmf8CTNvqdZQYp5cCKW0bUk69VygB2PuTiINFWbY78aR2pQw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@lmdb/lmdb-darwin-x64": { + "version": "2.8.5", + "resolved": "https://registry.npmjs.org/@lmdb/lmdb-darwin-x64/-/lmdb-darwin-x64-2.8.5.tgz", + "integrity": "sha512-w/sLhN4T7MW1nB3R/U8WK5BgQLz904wh+/SmA2jD8NnF7BLLoUgflCNxOeSPOWp8geP6nP/+VjWzZVip7rZ1ug==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@lmdb/lmdb-linux-arm": { + "version": "2.8.5", + "resolved": "https://registry.npmjs.org/@lmdb/lmdb-linux-arm/-/lmdb-linux-arm-2.8.5.tgz", + "integrity": "sha512-c0TGMbm2M55pwTDIfkDLB6BpIsgxV4PjYck2HiOX+cy/JWiBXz32lYbarPqejKs9Flm7YVAKSILUducU9g2RVg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@lmdb/lmdb-linux-arm64": { + "version": "2.8.5", + "resolved": "https://registry.npmjs.org/@lmdb/lmdb-linux-arm64/-/lmdb-linux-arm64-2.8.5.tgz", + "integrity": "sha512-vtbZRHH5UDlL01TT5jB576Zox3+hdyogvpcbvVJlmU5PdL3c5V7cj1EODdh1CHPksRl+cws/58ugEHi8bcj4Ww==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@lmdb/lmdb-linux-x64": { + "version": "2.8.5", + "resolved": "https://registry.npmjs.org/@lmdb/lmdb-linux-x64/-/lmdb-linux-x64-2.8.5.tgz", + "integrity": "sha512-Xkc8IUx9aEhP0zvgeKy7IQ3ReX2N8N1L0WPcQwnZweWmOuKfwpS3GRIYqLtK5za/w3E60zhFfNdS+3pBZPytqQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@lmdb/lmdb-win32-x64": { + "version": "2.8.5", + "resolved": "https://registry.npmjs.org/@lmdb/lmdb-win32-x64/-/lmdb-win32-x64-2.8.5.tgz", + "integrity": "sha512-4wvrf5BgnR8RpogHhtpCPJMKBmvyZPhhUtEwMJbXh0ni2BucpfF07jlmyM11zRqQ2XIq6PbC2j7W7UCCcm1rRQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@mischnic/json-sourcemap": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@mischnic/json-sourcemap/-/json-sourcemap-0.1.1.tgz", + "integrity": "sha512-iA7+tyVqfrATAIsIRWQG+a7ZLLD0VaOCKV2Wd/v4mqIU3J9c4jx9p7S0nw1XH3gJCKNBOOwACOPYYSUu9pgT+w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@lezer/common": "^1.0.0", + "@lezer/lr": "^1.0.0", + "json5": "^2.2.1" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/@msgpackr-extract/msgpackr-extract-darwin-arm64": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-darwin-arm64/-/msgpackr-extract-darwin-arm64-3.0.3.tgz", + "integrity": "sha512-QZHtlVgbAdy2zAqNA9Gu1UpIuI8Xvsd1v8ic6B2pZmeFnFcMWiPLfWXh7TVw4eGEZ/C9TH281KwhVoeQUKbyjw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@msgpackr-extract/msgpackr-extract-darwin-x64": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-darwin-x64/-/msgpackr-extract-darwin-x64-3.0.3.tgz", + "integrity": "sha512-mdzd3AVzYKuUmiWOQ8GNhl64/IoFGol569zNRdkLReh6LRLHOXxU4U8eq0JwaD8iFHdVGqSy4IjFL4reoWCDFw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@msgpackr-extract/msgpackr-extract-linux-arm": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-linux-arm/-/msgpackr-extract-linux-arm-3.0.3.tgz", + "integrity": "sha512-fg0uy/dG/nZEXfYilKoRe7yALaNmHoYeIoJuJ7KJ+YyU2bvY8vPv27f7UKhGRpY6euFYqEVhxCFZgAUNQBM3nw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@msgpackr-extract/msgpackr-extract-linux-arm64": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-linux-arm64/-/msgpackr-extract-linux-arm64-3.0.3.tgz", + "integrity": "sha512-YxQL+ax0XqBJDZiKimS2XQaf+2wDGVa1enVRGzEvLLVFeqa5kx2bWbtcSXgsxjQB7nRqqIGFIcLteF/sHeVtQg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@msgpackr-extract/msgpackr-extract-linux-x64": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-linux-x64/-/msgpackr-extract-linux-x64-3.0.3.tgz", + "integrity": "sha512-cvwNfbP07pKUfq1uH+S6KJ7dT9K8WOE4ZiAcsrSes+UY55E/0jLYc+vq+DO7jlmqRb5zAggExKm0H7O/CBaesg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@msgpackr-extract/msgpackr-extract-win32-x64": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-win32-x64/-/msgpackr-extract-win32-x64-3.0.3.tgz", + "integrity": "sha512-x0fWaQtYp4E6sktbsdAqnehxDgEc/VwM7uLsRCYWaiGu0ykYdZPiS8zCWdnjHwyiumousxfBm4SO31eXqwEZhQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@parcel/bundler-default": { + "version": "2.13.3", + "resolved": "https://registry.npmjs.org/@parcel/bundler-default/-/bundler-default-2.13.3.tgz", + "integrity": "sha512-mOuWeth0bZzRv1b9Lrvydis/hAzJyePy0gwa0tix3/zyYBvw0JY+xkXVR4qKyD/blc1Ra2qOlfI2uD3ucnsdXA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@parcel/diagnostic": "2.13.3", + "@parcel/graph": "3.3.3", + "@parcel/plugin": "2.13.3", + "@parcel/rust": "2.13.3", + "@parcel/utils": "2.13.3", + "nullthrows": "^1.1.1" + }, + "engines": { + "node": ">= 16.0.0", + "parcel": "^2.13.3" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/cache": { + "version": "2.13.3", + "resolved": "https://registry.npmjs.org/@parcel/cache/-/cache-2.13.3.tgz", + "integrity": "sha512-Vz5+K5uCt9mcuQAMDo0JdbPYDmVdB8Nvu/A2vTEK2rqZPxvoOTczKeMBA4JqzKqGURHPRLaJCvuR8nDG+jhK9A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@parcel/fs": "2.13.3", + "@parcel/logger": "2.13.3", + "@parcel/utils": "2.13.3", + "lmdb": "2.8.5" + }, + "engines": { + "node": ">= 16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + }, + "peerDependencies": { + "@parcel/core": "^2.13.3" + } + }, + "node_modules/@parcel/codeframe": { + "version": "2.13.3", + "resolved": "https://registry.npmjs.org/@parcel/codeframe/-/codeframe-2.13.3.tgz", + "integrity": "sha512-L/PQf+PT0xM8k9nc0B+PxxOYO2phQYnbuifu9o4pFRiqVmCtHztP+XMIvRJ2gOEXy3pgAImSPFVJ3xGxMFky4g==", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^4.1.2" + }, + "engines": { + "node": ">= 16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/compressor-raw": { + "version": "2.13.3", + "resolved": "https://registry.npmjs.org/@parcel/compressor-raw/-/compressor-raw-2.13.3.tgz", + "integrity": "sha512-C6vjDlgTLjYc358i7LA/dqcL0XDQZ1IHXFw6hBaHHOfxPKW2T4bzUI6RURyToEK9Q1X7+ggDKqgdLxwp4veCFg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@parcel/plugin": "2.13.3" + }, + "engines": { + "node": ">= 16.0.0", + "parcel": "^2.13.3" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/config-default": { + "version": "2.13.3", + "resolved": "https://registry.npmjs.org/@parcel/config-default/-/config-default-2.13.3.tgz", + "integrity": "sha512-WUsx83ic8DgLwwnL1Bua4lRgQqYjxiTT+DBxESGk1paNm1juWzyfPXEQDLXwiCTcWMQGiXQFQ8OuSISauVQ8dQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@parcel/bundler-default": "2.13.3", + "@parcel/compressor-raw": "2.13.3", + "@parcel/namer-default": "2.13.3", + "@parcel/optimizer-css": "2.13.3", + "@parcel/optimizer-htmlnano": "2.13.3", + "@parcel/optimizer-image": "2.13.3", + "@parcel/optimizer-svgo": "2.13.3", + "@parcel/optimizer-swc": "2.13.3", + "@parcel/packager-css": "2.13.3", + "@parcel/packager-html": "2.13.3", + "@parcel/packager-js": "2.13.3", + "@parcel/packager-raw": "2.13.3", + "@parcel/packager-svg": "2.13.3", + "@parcel/packager-wasm": "2.13.3", + "@parcel/reporter-dev-server": "2.13.3", + "@parcel/resolver-default": "2.13.3", + "@parcel/runtime-browser-hmr": "2.13.3", + "@parcel/runtime-js": "2.13.3", + "@parcel/runtime-react-refresh": "2.13.3", + "@parcel/runtime-service-worker": "2.13.3", + "@parcel/transformer-babel": "2.13.3", + "@parcel/transformer-css": "2.13.3", + "@parcel/transformer-html": "2.13.3", + "@parcel/transformer-image": "2.13.3", + "@parcel/transformer-js": "2.13.3", + "@parcel/transformer-json": "2.13.3", + "@parcel/transformer-postcss": "2.13.3", + "@parcel/transformer-posthtml": "2.13.3", + "@parcel/transformer-raw": "2.13.3", + "@parcel/transformer-react-refresh-wrap": "2.13.3", + "@parcel/transformer-svg": "2.13.3" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + }, + "peerDependencies": { + "@parcel/core": "^2.13.3" + } + }, + "node_modules/@parcel/core": { + "version": "2.13.3", + "resolved": "https://registry.npmjs.org/@parcel/core/-/core-2.13.3.tgz", + "integrity": "sha512-SRZFtqGiaKHlZ2YAvf+NHvBFWS3GnkBvJMfOJM7kxJRK3M1bhbwJa/GgSdzqro5UVf9Bfj6E+pkdrRQIOZ7jMQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@mischnic/json-sourcemap": "^0.1.0", + "@parcel/cache": "2.13.3", + "@parcel/diagnostic": "2.13.3", + "@parcel/events": "2.13.3", + "@parcel/feature-flags": "2.13.3", + "@parcel/fs": "2.13.3", + "@parcel/graph": "3.3.3", + "@parcel/logger": "2.13.3", + "@parcel/package-manager": "2.13.3", + "@parcel/plugin": "2.13.3", + "@parcel/profiler": "2.13.3", + "@parcel/rust": "2.13.3", + "@parcel/source-map": "^2.1.1", + "@parcel/types": "2.13.3", + "@parcel/utils": "2.13.3", + "@parcel/workers": "2.13.3", + "base-x": "^3.0.8", + "browserslist": "^4.6.6", + "clone": "^2.1.1", + "dotenv": "^16.4.5", + "dotenv-expand": "^11.0.6", + "json5": "^2.2.0", + "msgpackr": "^1.9.9", + "nullthrows": "^1.1.1", + "semver": "^7.5.2" + }, + "engines": { + "node": ">= 16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/diagnostic": { + "version": "2.13.3", + "resolved": "https://registry.npmjs.org/@parcel/diagnostic/-/diagnostic-2.13.3.tgz", + "integrity": "sha512-C70KXLBaXLJvr7XCEVu8m6TqNdw1gQLxqg5BQ8roR62R4vWWDnOq8PEksxDi4Y8Z/FF4i3Sapv6tRx9iBNxDEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@mischnic/json-sourcemap": "^0.1.0", + "nullthrows": "^1.1.1" + }, + "engines": { + "node": ">= 16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/events": { + "version": "2.13.3", + "resolved": "https://registry.npmjs.org/@parcel/events/-/events-2.13.3.tgz", + "integrity": "sha512-ZkSHTTbD/E+53AjUzhAWTnMLnxLEU5yRw0H614CaruGh+GjgOIKyukGeToF5Gf/lvZ159VrJCGE0Z5EpgHVkuQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/feature-flags": { + "version": "2.13.3", + "resolved": "https://registry.npmjs.org/@parcel/feature-flags/-/feature-flags-2.13.3.tgz", + "integrity": "sha512-UZm14QpamDFoUut9YtCZSpG1HxPs07lUwUCpsAYL0PpxASD3oWJQxIJGfDZPa2272DarXDG9adTKrNXvkHZblw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/fs": { + "version": "2.13.3", + "resolved": "https://registry.npmjs.org/@parcel/fs/-/fs-2.13.3.tgz", + "integrity": "sha512-+MPWAt0zr+TCDSlj1LvkORTjfB/BSffsE99A9AvScKytDSYYpY2s0t4vtV9unSh0FHMS2aBCZNJ4t7KL+DcPIg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@parcel/feature-flags": "2.13.3", + "@parcel/rust": "2.13.3", + "@parcel/types-internal": "2.13.3", + "@parcel/utils": "2.13.3", + "@parcel/watcher": "^2.0.7", + "@parcel/workers": "2.13.3" + }, + "engines": { + "node": ">= 16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + }, + "peerDependencies": { + "@parcel/core": "^2.13.3" + } + }, + "node_modules/@parcel/graph": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/@parcel/graph/-/graph-3.3.3.tgz", + "integrity": "sha512-pxs4GauEdvCN8nRd6wG3st6LvpHske3GfqGwUSR0P0X0pBPI1/NicvXz6xzp3rgb9gPWfbKXeI/2IOTfIxxVfg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@parcel/feature-flags": "2.13.3", + "nullthrows": "^1.1.1" + }, + "engines": { + "node": ">= 16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/logger": { + "version": "2.13.3", + "resolved": "https://registry.npmjs.org/@parcel/logger/-/logger-2.13.3.tgz", + "integrity": "sha512-8YF/ZhsQgd7ohQ2vEqcMD1Ag9JlJULROWRPGgGYLGD+twuxAiSdiFBpN3f+j4gQN4PYaLaIS/SwUFx11J243fQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@parcel/diagnostic": "2.13.3", + "@parcel/events": "2.13.3" + }, + "engines": { + "node": ">= 16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/markdown-ansi": { + "version": "2.13.3", + "resolved": "https://registry.npmjs.org/@parcel/markdown-ansi/-/markdown-ansi-2.13.3.tgz", + "integrity": "sha512-B4rUdlNUulJs2xOQuDbN7Hq5a9roq8IZUcJ1vQ8PAv+zMGb7KCfqIIr/BSCDYGhayfAGBVWW8x55Kvrl1zrDYw==", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^4.1.2" + }, + "engines": { + "node": ">= 16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/namer-default": { + "version": "2.13.3", + "resolved": "https://registry.npmjs.org/@parcel/namer-default/-/namer-default-2.13.3.tgz", + "integrity": "sha512-A2a5A5fuyNcjSGOS0hPcdQmOE2kszZnLIXof7UMGNkNkeC62KAG8WcFZH5RNOY3LT5H773hq51zmc2Y2gE5Rnw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@parcel/diagnostic": "2.13.3", + "@parcel/plugin": "2.13.3", + "nullthrows": "^1.1.1" + }, + "engines": { + "node": ">= 16.0.0", + "parcel": "^2.13.3" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/node-resolver-core": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/@parcel/node-resolver-core/-/node-resolver-core-3.4.3.tgz", + "integrity": "sha512-IEnMks49egEic1ITBp59VQyHzkSQUXqpU9hOHwqN3KoSTdZ6rEgrXcS3pa6tdXay4NYGlcZ88kFCE8i/xYoVCg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@mischnic/json-sourcemap": "^0.1.0", + "@parcel/diagnostic": "2.13.3", + "@parcel/fs": "2.13.3", + "@parcel/rust": "2.13.3", + "@parcel/utils": "2.13.3", + "nullthrows": "^1.1.1", + "semver": "^7.5.2" + }, + "engines": { + "node": ">= 16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/optimizer-css": { + "version": "2.13.3", + "resolved": "https://registry.npmjs.org/@parcel/optimizer-css/-/optimizer-css-2.13.3.tgz", + "integrity": "sha512-A8o9IVCv919vhv69SkLmyW2WjJR5WZgcMqV6L1uiGF8i8z18myrMhrp2JuSHx29PRT9uNyzNC4Xrd4StYjIhJg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@parcel/diagnostic": "2.13.3", + "@parcel/plugin": "2.13.3", + "@parcel/source-map": "^2.1.1", + "@parcel/utils": "2.13.3", + "browserslist": "^4.6.6", + "lightningcss": "^1.22.1", + "nullthrows": "^1.1.1" + }, + "engines": { + "node": ">= 16.0.0", + "parcel": "^2.13.3" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/optimizer-htmlnano": { + "version": "2.13.3", + "resolved": "https://registry.npmjs.org/@parcel/optimizer-htmlnano/-/optimizer-htmlnano-2.13.3.tgz", + "integrity": "sha512-K4Uvg0Sy2pECP7pdvvbud++F0pfcbNkq+IxTrgqBX5HJnLEmRZwgdvZEKF43oMEolclMnURMQRGjRplRaPdbXg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@parcel/diagnostic": "2.13.3", + "@parcel/plugin": "2.13.3", + "@parcel/utils": "2.13.3", + "htmlnano": "^2.0.0", + "nullthrows": "^1.1.1", + "posthtml": "^0.16.5" + }, + "engines": { + "node": ">= 16.0.0", + "parcel": "^2.13.3" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/optimizer-image": { + "version": "2.13.3", + "resolved": "https://registry.npmjs.org/@parcel/optimizer-image/-/optimizer-image-2.13.3.tgz", + "integrity": "sha512-wlDUICA29J4UnqkKrWiyt68g1e85qfYhp4zJFcFJL0LX1qqh1QwsLUz3YJ+KlruoqPxJSFEC8ncBEKiVCsqhEQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@parcel/diagnostic": "2.13.3", + "@parcel/plugin": "2.13.3", + "@parcel/rust": "2.13.3", + "@parcel/utils": "2.13.3", + "@parcel/workers": "2.13.3" + }, + "engines": { + "node": ">= 16.0.0", + "parcel": "^2.13.3" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + }, + "peerDependencies": { + "@parcel/core": "^2.13.3" + } + }, + "node_modules/@parcel/optimizer-svgo": { + "version": "2.13.3", + "resolved": "https://registry.npmjs.org/@parcel/optimizer-svgo/-/optimizer-svgo-2.13.3.tgz", + "integrity": "sha512-piIKxQKzhZK54dJR6yqIcq+urZmpsfgUpLCZT3cnWlX4ux5+S2iN66qqZBs0zVn+a58LcWcoP4Z9ieiJmpiu2w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@parcel/diagnostic": "2.13.3", + "@parcel/plugin": "2.13.3", + "@parcel/utils": "2.13.3" + }, + "engines": { + "node": ">= 16.0.0", + "parcel": "^2.13.3" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/optimizer-swc": { + "version": "2.13.3", + "resolved": "https://registry.npmjs.org/@parcel/optimizer-swc/-/optimizer-swc-2.13.3.tgz", + "integrity": "sha512-zNSq6oWqLlW8ksPIDjM0VgrK6ZAJbPQCDvs1V+p0oX3CzEe85lT5VkRpnfrN1+/vvEJNGL8e60efHKpI+rXGTA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@parcel/diagnostic": "2.13.3", + "@parcel/plugin": "2.13.3", + "@parcel/source-map": "^2.1.1", + "@parcel/utils": "2.13.3", + "@swc/core": "^1.7.26", + "nullthrows": "^1.1.1" + }, + "engines": { + "node": ">= 16.0.0", + "parcel": "^2.13.3" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/package-manager": { + "version": "2.13.3", + "resolved": "https://registry.npmjs.org/@parcel/package-manager/-/package-manager-2.13.3.tgz", + "integrity": "sha512-FLNI5OrZxymGf/Yln0E/kjnGn5sdkQAxW7pQVdtuM+5VeN75yibJRjsSGv88PvJ+KvpD2ANgiIJo1RufmoPcww==", + "dev": true, + "license": "MIT", + "dependencies": { + "@parcel/diagnostic": "2.13.3", + "@parcel/fs": "2.13.3", + "@parcel/logger": "2.13.3", + "@parcel/node-resolver-core": "3.4.3", + "@parcel/types": "2.13.3", + "@parcel/utils": "2.13.3", + "@parcel/workers": "2.13.3", + "@swc/core": "^1.7.26", + "semver": "^7.5.2" + }, + "engines": { + "node": ">= 16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + }, + "peerDependencies": { + "@parcel/core": "^2.13.3" + } + }, + "node_modules/@parcel/packager-css": { + "version": "2.13.3", + "resolved": "https://registry.npmjs.org/@parcel/packager-css/-/packager-css-2.13.3.tgz", + "integrity": "sha512-ghDqRMtrUwaDERzFm9le0uz2PTeqqsjsW0ihQSZPSAptElRl9o5BR+XtMPv3r7Ui0evo+w35gD55oQCJ28vCig==", + "dev": true, + "license": "MIT", + "dependencies": { + "@parcel/diagnostic": "2.13.3", + "@parcel/plugin": "2.13.3", + "@parcel/source-map": "^2.1.1", + "@parcel/utils": "2.13.3", + "lightningcss": "^1.22.1", + "nullthrows": "^1.1.1" + }, + "engines": { + "node": ">= 16.0.0", + "parcel": "^2.13.3" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/packager-html": { + "version": "2.13.3", + "resolved": "https://registry.npmjs.org/@parcel/packager-html/-/packager-html-2.13.3.tgz", + "integrity": "sha512-jDLnKSA/EzVEZ3/aegXO3QJ/Ij732AgBBkIQfeC8tUoxwVz5b3HiPBAjVjcUSfZs7mdBSHO+ELWC3UD+HbsIrQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@parcel/plugin": "2.13.3", + "@parcel/types": "2.13.3", + "@parcel/utils": "2.13.3", + "nullthrows": "^1.1.1", + "posthtml": "^0.16.5" + }, + "engines": { + "node": ">= 16.0.0", + "parcel": "^2.13.3" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/packager-js": { + "version": "2.13.3", + "resolved": "https://registry.npmjs.org/@parcel/packager-js/-/packager-js-2.13.3.tgz", + "integrity": "sha512-0pMHHf2zOn7EOJe88QJw5h/wcV1bFfj6cXVcE55Wa8GX3V+SdCgolnlvNuBcRQ1Tlx0Xkpo+9hMFVIQbNQY6zw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@parcel/diagnostic": "2.13.3", + "@parcel/plugin": "2.13.3", + "@parcel/rust": "2.13.3", + "@parcel/source-map": "^2.1.1", + "@parcel/types": "2.13.3", + "@parcel/utils": "2.13.3", + "globals": "^13.2.0", + "nullthrows": "^1.1.1" + }, + "engines": { + "node": ">= 16.0.0", + "parcel": "^2.13.3" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/packager-raw": { + "version": "2.13.3", + "resolved": "https://registry.npmjs.org/@parcel/packager-raw/-/packager-raw-2.13.3.tgz", + "integrity": "sha512-AWu4UB+akBdskzvT3KGVHIdacU9f7cI678DQQ1jKQuc9yZz5D0VFt3ocFBOmvDfEQDF0uH3jjtJR7fnuvX7Biw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@parcel/plugin": "2.13.3" + }, + "engines": { + "node": ">= 16.0.0", + "parcel": "^2.13.3" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/packager-svg": { + "version": "2.13.3", + "resolved": "https://registry.npmjs.org/@parcel/packager-svg/-/packager-svg-2.13.3.tgz", + "integrity": "sha512-tKGRiFq/4jh5u2xpTstNQ7gu+RuZWzlWqpw5NaFmcKe6VQe5CMcS499xTFoREAGnRvevSeIgC38X1a+VOo+/AA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@parcel/plugin": "2.13.3", + "@parcel/types": "2.13.3", + "@parcel/utils": "2.13.3", + "posthtml": "^0.16.4" + }, + "engines": { + "node": ">= 16.0.0", + "parcel": "^2.13.3" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/packager-wasm": { + "version": "2.13.3", + "resolved": "https://registry.npmjs.org/@parcel/packager-wasm/-/packager-wasm-2.13.3.tgz", + "integrity": "sha512-SZB56/b230vFrSehVXaUAWjJmWYc89gzb8OTLkBm7uvtFtov2J1R8Ig9TTJwinyXE3h84MCFP/YpQElSfoLkJw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@parcel/plugin": "2.13.3" + }, + "engines": { + "node": ">=16.0.0", + "parcel": "^2.13.3" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/plugin": { + "version": "2.13.3", + "resolved": "https://registry.npmjs.org/@parcel/plugin/-/plugin-2.13.3.tgz", + "integrity": "sha512-cterKHHcwg6q11Gpif/aqvHo056TR+yDVJ3fSdiG2xr5KD1VZ2B3hmofWERNNwjMcnR1h9Xq40B7jCKUhOyNFA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@parcel/types": "2.13.3" + }, + "engines": { + "node": ">= 16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/profiler": { + "version": "2.13.3", + "resolved": "https://registry.npmjs.org/@parcel/profiler/-/profiler-2.13.3.tgz", + "integrity": "sha512-ok6BwWSLvyHe5TuSXjSacYnDStFgP5Y30tA9mbtWSm0INDsYf+m5DqzpYPx8U54OaywWMK8w3MXUClosJX3aPA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@parcel/diagnostic": "2.13.3", + "@parcel/events": "2.13.3", + "@parcel/types-internal": "2.13.3", + "chrome-trace-event": "^1.0.2" + }, + "engines": { + "node": ">= 16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/reporter-cli": { + "version": "2.13.3", + "resolved": "https://registry.npmjs.org/@parcel/reporter-cli/-/reporter-cli-2.13.3.tgz", + "integrity": "sha512-EA5tKt/6bXYNMEavSs35qHlFdx6cZmRazlZxPBgxPePQYoouNAPMNLUOEQozaPhz9f5fvNDN7EHOFaAWcdO2LA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@parcel/plugin": "2.13.3", + "@parcel/types": "2.13.3", + "@parcel/utils": "2.13.3", + "chalk": "^4.1.2", + "term-size": "^2.2.1" + }, + "engines": { + "node": ">= 16.0.0", + "parcel": "^2.13.3" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/reporter-dev-server": { + "version": "2.13.3", + "resolved": "https://registry.npmjs.org/@parcel/reporter-dev-server/-/reporter-dev-server-2.13.3.tgz", + "integrity": "sha512-ZNeFp6AOIQFv7mZIv2P5O188dnZHNg0ymeDVcakfZomwhpSva2dFNS3AnvWo4eyWBlUxkmQO8BtaxeWTs7jAuA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@parcel/plugin": "2.13.3", + "@parcel/utils": "2.13.3" + }, + "engines": { + "node": ">= 16.0.0", + "parcel": "^2.13.3" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/reporter-tracer": { + "version": "2.13.3", + "resolved": "https://registry.npmjs.org/@parcel/reporter-tracer/-/reporter-tracer-2.13.3.tgz", + "integrity": "sha512-aBsVPI8jLZTDkFYrI69GxnsdvZKEYerkPsu935LcX9rfUYssOnmmUP+3oI+8fbg+qNjJuk9BgoQ4hCp9FOphMQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@parcel/plugin": "2.13.3", + "@parcel/utils": "2.13.3", + "chrome-trace-event": "^1.0.3", + "nullthrows": "^1.1.1" + }, + "engines": { + "node": ">= 16.0.0", + "parcel": "^2.13.3" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/resolver-default": { + "version": "2.13.3", + "resolved": "https://registry.npmjs.org/@parcel/resolver-default/-/resolver-default-2.13.3.tgz", + "integrity": "sha512-urBZuRALWT9pFMeWQ8JirchLmsQEyI9lrJptiwLbJWrwvmlwSUGkcstmPwoNRf/aAQjICB7ser/247Vny0pFxA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@parcel/node-resolver-core": "3.4.3", + "@parcel/plugin": "2.13.3" + }, + "engines": { + "node": ">= 16.0.0", + "parcel": "^2.13.3" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/runtime-browser-hmr": { + "version": "2.13.3", + "resolved": "https://registry.npmjs.org/@parcel/runtime-browser-hmr/-/runtime-browser-hmr-2.13.3.tgz", + "integrity": "sha512-EAcPojQFUNUGUrDk66cu3ySPO0NXRVS5CKPd4QrxPCVVbGzde4koKu8krC/TaGsoyUqhie8HMnS70qBP0GFfcQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@parcel/plugin": "2.13.3", + "@parcel/utils": "2.13.3" + }, + "engines": { + "node": ">= 16.0.0", + "parcel": "^2.13.3" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/runtime-js": { + "version": "2.13.3", + "resolved": "https://registry.npmjs.org/@parcel/runtime-js/-/runtime-js-2.13.3.tgz", + "integrity": "sha512-62OucNAnxb2Q0uyTFWW/0Hvv2DJ4b5H6neh/YFu2/wmxaZ37xTpEuEcG2do7KW54xE5DeLP+RliHLwi4NvR3ww==", + "dev": true, + "license": "MIT", + "dependencies": { + "@parcel/diagnostic": "2.13.3", + "@parcel/plugin": "2.13.3", + "@parcel/utils": "2.13.3", + "nullthrows": "^1.1.1" + }, + "engines": { + "node": ">= 16.0.0", + "parcel": "^2.13.3" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/runtime-react-refresh": { + "version": "2.13.3", + "resolved": "https://registry.npmjs.org/@parcel/runtime-react-refresh/-/runtime-react-refresh-2.13.3.tgz", + "integrity": "sha512-PYZ1klpJVwqE3WuifILjtF1dugtesHEuJcXYZI85T6UoRSD5ctS1nAIpZzT14Ga1lRt/jd+eAmhWL1l3m/Vk1Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@parcel/plugin": "2.13.3", + "@parcel/utils": "2.13.3", + "react-error-overlay": "6.0.9", + "react-refresh": ">=0.9 <=0.14" + }, + "engines": { + "node": ">= 16.0.0", + "parcel": "^2.13.3" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/runtime-service-worker": { + "version": "2.13.3", + "resolved": "https://registry.npmjs.org/@parcel/runtime-service-worker/-/runtime-service-worker-2.13.3.tgz", + "integrity": "sha512-BjMhPuT7Us1+YIo31exPRwomPiL+jrZZS5UUAwlEW2XGHDceEotzRM94LwxeFliCScT4IOokGoxixm19qRuzWg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@parcel/plugin": "2.13.3", + "@parcel/utils": "2.13.3", + "nullthrows": "^1.1.1" + }, + "engines": { + "node": ">= 16.0.0", + "parcel": "^2.13.3" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/rust": { + "version": "2.13.3", + "resolved": "https://registry.npmjs.org/@parcel/rust/-/rust-2.13.3.tgz", + "integrity": "sha512-dLq85xDAtzr3P5200cvxk+8WXSWauYbxuev9LCPdwfhlaWo/JEj6cu9seVdWlkagjGwkoV1kXC+GGntgUXOLAQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/source-map": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@parcel/source-map/-/source-map-2.1.1.tgz", + "integrity": "sha512-Ejx1P/mj+kMjQb8/y5XxDUn4reGdr+WyKYloBljpppUy8gs42T+BNoEOuRYqDVdgPc6NxduzIDoJS9pOFfV5Ew==", + "dev": true, + "license": "MIT", + "dependencies": { + "detect-libc": "^1.0.3" + }, + "engines": { + "node": "^12.18.3 || >=14" + } + }, + "node_modules/@parcel/transformer-babel": { + "version": "2.13.3", + "resolved": "https://registry.npmjs.org/@parcel/transformer-babel/-/transformer-babel-2.13.3.tgz", + "integrity": "sha512-ikzK9f5WTFrdQsPitQgjCPH6HmVU8AQPRemIJ2BndYhtodn5PQut5cnSvTrqax8RjYvheEKCQk/Zb/uR7qgS3g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@parcel/diagnostic": "2.13.3", + "@parcel/plugin": "2.13.3", + "@parcel/source-map": "^2.1.1", + "@parcel/utils": "2.13.3", + "browserslist": "^4.6.6", + "json5": "^2.2.0", + "nullthrows": "^1.1.1", + "semver": "^7.5.2" + }, + "engines": { + "node": ">= 16.0.0", + "parcel": "^2.13.3" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/transformer-css": { + "version": "2.13.3", + "resolved": "https://registry.npmjs.org/@parcel/transformer-css/-/transformer-css-2.13.3.tgz", + "integrity": "sha512-zbrNURGph6JeVADbGydyZ7lcu/izj41kDxQ9xw4RPRW/3rofQiTU0OTREi+uBWiMENQySXVivEdzHA9cA+aLAA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@parcel/diagnostic": "2.13.3", + "@parcel/plugin": "2.13.3", + "@parcel/source-map": "^2.1.1", + "@parcel/utils": "2.13.3", + "browserslist": "^4.6.6", + "lightningcss": "^1.22.1", + "nullthrows": "^1.1.1" + }, + "engines": { + "node": ">= 16.0.0", + "parcel": "^2.13.3" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/transformer-html": { + "version": "2.13.3", + "resolved": "https://registry.npmjs.org/@parcel/transformer-html/-/transformer-html-2.13.3.tgz", + "integrity": "sha512-Yf74FkL9RCCB4+hxQRVMNQThH9+fZ5w0NLiQPpWUOcgDEEyxTi4FWPQgEBsKl/XK2ehdydbQB9fBgPQLuQxwPg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@parcel/diagnostic": "2.13.3", + "@parcel/plugin": "2.13.3", + "@parcel/rust": "2.13.3", + "nullthrows": "^1.1.1", + "posthtml": "^0.16.5", + "posthtml-parser": "^0.12.1", + "posthtml-render": "^3.0.0", + "semver": "^7.5.2", + "srcset": "4" + }, + "engines": { + "node": ">= 16.0.0", + "parcel": "^2.13.3" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/transformer-html/node_modules/srcset": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/srcset/-/srcset-4.0.0.tgz", + "integrity": "sha512-wvLeHgcVHKO8Sc/H/5lkGreJQVeYMm9rlmt8PuR1xE31rIuXhuzznUUqAt8MqLhB3MqJdFzlNAfpcWnxiFUcPw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@parcel/transformer-image": { + "version": "2.13.3", + "resolved": "https://registry.npmjs.org/@parcel/transformer-image/-/transformer-image-2.13.3.tgz", + "integrity": "sha512-wL1CXyeFAqbp2wcEq/JD3a/tbAyVIDMTC6laQxlIwnVV7dsENhK1qRuJZuoBdixESeUpFQSmmQvDIhcfT/cUUg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@parcel/plugin": "2.13.3", + "@parcel/utils": "2.13.3", + "@parcel/workers": "2.13.3", + "nullthrows": "^1.1.1" + }, + "engines": { + "node": ">= 16.0.0", + "parcel": "^2.13.3" + }, + "peerDependencies": { + "@parcel/core": "^2.13.3" + } + }, + "node_modules/@parcel/transformer-js": { + "version": "2.13.3", + "resolved": "https://registry.npmjs.org/@parcel/transformer-js/-/transformer-js-2.13.3.tgz", + "integrity": "sha512-KqfNGn1IHzDoN2aPqt4nDksgb50Xzcny777C7A7hjlQ3cmkjyJrixYjzzsPaPSGJ+kJpknh3KE8unkQ9mhFvRQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@parcel/diagnostic": "2.13.3", + "@parcel/plugin": "2.13.3", + "@parcel/rust": "2.13.3", + "@parcel/source-map": "^2.1.1", + "@parcel/utils": "2.13.3", + "@parcel/workers": "2.13.3", + "@swc/helpers": "^0.5.0", + "browserslist": "^4.6.6", + "nullthrows": "^1.1.1", + "regenerator-runtime": "^0.14.1", + "semver": "^7.5.2" + }, + "engines": { + "node": ">= 16.0.0", + "parcel": "^2.13.3" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + }, + "peerDependencies": { + "@parcel/core": "^2.13.3" + } + }, + "node_modules/@parcel/transformer-json": { + "version": "2.13.3", + "resolved": "https://registry.npmjs.org/@parcel/transformer-json/-/transformer-json-2.13.3.tgz", + "integrity": "sha512-rrq0ab6J0w9ePtsxi0kAvpCmrUYXXAx1Z5PATZakv89rSYbHBKEdXxyCoKFui/UPVCUEGVs5r0iOFepdHpIyeA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@parcel/plugin": "2.13.3", + "json5": "^2.2.0" + }, + "engines": { + "node": ">= 16.0.0", + "parcel": "^2.13.3" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/transformer-postcss": { + "version": "2.13.3", + "resolved": "https://registry.npmjs.org/@parcel/transformer-postcss/-/transformer-postcss-2.13.3.tgz", + "integrity": "sha512-AIiWpU0QSFBrPcYIqAnhqB8RGE6yHFznnxztfg1t2zMSOnK3xoU6xqYKv8H/MduShGGrC3qVOeDfM8MUwzL3cw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@parcel/diagnostic": "2.13.3", + "@parcel/plugin": "2.13.3", + "@parcel/rust": "2.13.3", + "@parcel/utils": "2.13.3", + "clone": "^2.1.1", + "nullthrows": "^1.1.1", + "postcss-value-parser": "^4.2.0", + "semver": "^7.5.2" + }, + "engines": { + "node": ">= 16.0.0", + "parcel": "^2.13.3" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/transformer-posthtml": { + "version": "2.13.3", + "resolved": "https://registry.npmjs.org/@parcel/transformer-posthtml/-/transformer-posthtml-2.13.3.tgz", + "integrity": "sha512-5GSLyccpHASwFAu3uJ83gDIBSvfsGdVmhJvy0Vxe+K1Fklk2ibhvvtUHMhB7mg6SPHC+R9jsNc3ZqY04ZLeGjw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@parcel/plugin": "2.13.3", + "@parcel/utils": "2.13.3", + "nullthrows": "^1.1.1", + "posthtml": "^0.16.5", + "posthtml-parser": "^0.12.1", + "posthtml-render": "^3.0.0", + "semver": "^7.5.2" + }, + "engines": { + "node": ">= 16.0.0", + "parcel": "^2.13.3" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/transformer-raw": { + "version": "2.13.3", + "resolved": "https://registry.npmjs.org/@parcel/transformer-raw/-/transformer-raw-2.13.3.tgz", + "integrity": "sha512-BFsAbdQF0l8/Pdb7dSLJeYcd8jgwvAUbHgMink2MNXJuRUvDl19Gns8jVokU+uraFHulJMBj40+K/RTd33in4g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@parcel/plugin": "2.13.3" + }, + "engines": { + "node": ">= 16.0.0", + "parcel": "^2.13.3" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/transformer-react-refresh-wrap": { + "version": "2.13.3", + "resolved": "https://registry.npmjs.org/@parcel/transformer-react-refresh-wrap/-/transformer-react-refresh-wrap-2.13.3.tgz", + "integrity": "sha512-mOof4cRyxsZRdg8kkWaFtaX98mHpxUhcGPU+nF9RQVa9q737ItxrorsPNR9hpZAyE2TtFNflNW7RoYsgvlLw8w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@parcel/plugin": "2.13.3", + "@parcel/utils": "2.13.3", + "react-refresh": ">=0.9 <=0.14" + }, + "engines": { + "node": ">= 16.0.0", + "parcel": "^2.13.3" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/transformer-svg": { + "version": "2.13.3", + "resolved": "https://registry.npmjs.org/@parcel/transformer-svg/-/transformer-svg-2.13.3.tgz", + "integrity": "sha512-9jm7ZF4KHIrGLWlw/SFUz5KKJ20nxHvjFAmzde34R9Wu+F1BOjLZxae7w4ZRwvIc+UVOUcBBQFmhSVwVDZg6Dw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@parcel/diagnostic": "2.13.3", + "@parcel/plugin": "2.13.3", + "@parcel/rust": "2.13.3", + "nullthrows": "^1.1.1", + "posthtml": "^0.16.5", + "posthtml-parser": "^0.12.1", + "posthtml-render": "^3.0.0", + "semver": "^7.5.2" + }, + "engines": { + "node": ">= 16.0.0", + "parcel": "^2.13.3" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/types": { + "version": "2.13.3", + "resolved": "https://registry.npmjs.org/@parcel/types/-/types-2.13.3.tgz", + "integrity": "sha512-+RpFHxx8fy8/dpuehHUw/ja9PRExC3wJoIlIIF42E7SLu2SvlTHtKm6EfICZzxCXNEBzjoDbamCRcN0nmTPlhw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@parcel/types-internal": "2.13.3", + "@parcel/workers": "2.13.3" + } + }, + "node_modules/@parcel/types-internal": { + "version": "2.13.3", + "resolved": "https://registry.npmjs.org/@parcel/types-internal/-/types-internal-2.13.3.tgz", + "integrity": "sha512-Lhx0n+9RCp+Ipktf/I+CLm3zE9Iq9NtDd8b2Vr5lVWyoT8AbzBKIHIpTbhLS4kjZ80L3I6o93OYjqAaIjsqoZw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@parcel/diagnostic": "2.13.3", + "@parcel/feature-flags": "2.13.3", + "@parcel/source-map": "^2.1.1", + "utility-types": "^3.10.0" + } + }, + "node_modules/@parcel/utils": { + "version": "2.13.3", + "resolved": "https://registry.npmjs.org/@parcel/utils/-/utils-2.13.3.tgz", + "integrity": "sha512-yxY9xw2wOUlJaScOXYZmMGoZ4Ck4Kqj+p6Koe5kLkkWM1j98Q0Dj2tf/mNvZi4yrdnlm+dclCwNRnuE8Q9D+pw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@parcel/codeframe": "2.13.3", + "@parcel/diagnostic": "2.13.3", + "@parcel/logger": "2.13.3", + "@parcel/markdown-ansi": "2.13.3", + "@parcel/rust": "2.13.3", + "@parcel/source-map": "^2.1.1", + "chalk": "^4.1.2", + "nullthrows": "^1.1.1" + }, + "engines": { + "node": ">= 16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher/-/watcher-2.5.1.tgz", + "integrity": "sha512-dfUnCxiN9H4ap84DvD2ubjw+3vUNpstxa0TneY/Paat8a3R4uQZDLSvWjmznAY/DoahqTHl9V46HF/Zs3F29pg==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "dependencies": { + "detect-libc": "^1.0.3", + "is-glob": "^4.0.3", + "micromatch": "^4.0.5", + "node-addon-api": "^7.0.0" + }, + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + }, + "optionalDependencies": { + "@parcel/watcher-android-arm64": "2.5.1", + "@parcel/watcher-darwin-arm64": "2.5.1", + "@parcel/watcher-darwin-x64": "2.5.1", + "@parcel/watcher-freebsd-x64": "2.5.1", + "@parcel/watcher-linux-arm-glibc": "2.5.1", + "@parcel/watcher-linux-arm-musl": "2.5.1", + "@parcel/watcher-linux-arm64-glibc": "2.5.1", + "@parcel/watcher-linux-arm64-musl": "2.5.1", + "@parcel/watcher-linux-x64-glibc": "2.5.1", + "@parcel/watcher-linux-x64-musl": "2.5.1", + "@parcel/watcher-win32-arm64": "2.5.1", + "@parcel/watcher-win32-ia32": "2.5.1", + "@parcel/watcher-win32-x64": "2.5.1" + } + }, + "node_modules/@parcel/watcher-android-arm64": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-android-arm64/-/watcher-android-arm64-2.5.1.tgz", + "integrity": "sha512-KF8+j9nNbUN8vzOFDpRMsaKBHZ/mcjEjMToVMJOhTozkDonQFFrRcfdLWn6yWKCmJKmdVxSgHiYvTCef4/qcBA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-darwin-arm64": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-arm64/-/watcher-darwin-arm64-2.5.1.tgz", + "integrity": "sha512-eAzPv5osDmZyBhou8PoF4i6RQXAfeKL9tjb3QzYuccXFMQU0ruIc/POh30ePnaOyD1UXdlKguHBmsTs53tVoPw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-darwin-x64": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-x64/-/watcher-darwin-x64-2.5.1.tgz", + "integrity": "sha512-1ZXDthrnNmwv10A0/3AJNZ9JGlzrF82i3gNQcWOzd7nJ8aj+ILyW1MTxVk35Db0u91oD5Nlk9MBiujMlwmeXZg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-freebsd-x64": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-freebsd-x64/-/watcher-freebsd-x64-2.5.1.tgz", + "integrity": "sha512-SI4eljM7Flp9yPuKi8W0ird8TI/JK6CSxju3NojVI6BjHsTyK7zxA9urjVjEKJ5MBYC+bLmMcbAWlZ+rFkLpJQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-arm-glibc": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm-glibc/-/watcher-linux-arm-glibc-2.5.1.tgz", + "integrity": "sha512-RCdZlEyTs8geyBkkcnPWvtXLY44BCeZKmGYRtSgtwwnHR4dxfHRG3gR99XdMEdQ7KeiDdasJwwvNSF5jKtDwdA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-arm-musl": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm-musl/-/watcher-linux-arm-musl-2.5.1.tgz", + "integrity": "sha512-6E+m/Mm1t1yhB8X412stiKFG3XykmgdIOqhjWj+VL8oHkKABfu/gjFj8DvLrYVHSBNC+/u5PeNrujiSQ1zwd1Q==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-arm64-glibc": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-glibc/-/watcher-linux-arm64-glibc-2.5.1.tgz", + "integrity": "sha512-LrGp+f02yU3BN9A+DGuY3v3bmnFUggAITBGriZHUREfNEzZh/GO06FF5u2kx8x+GBEUYfyTGamol4j3m9ANe8w==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-arm64-musl": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-musl/-/watcher-linux-arm64-musl-2.5.1.tgz", + "integrity": "sha512-cFOjABi92pMYRXS7AcQv9/M1YuKRw8SZniCDw0ssQb/noPkRzA+HBDkwmyOJYp5wXcsTrhxO0zq1U11cK9jsFg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-x64-glibc": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-glibc/-/watcher-linux-x64-glibc-2.5.1.tgz", + "integrity": "sha512-GcESn8NZySmfwlTsIur+49yDqSny2IhPeZfXunQi48DMugKeZ7uy1FX83pO0X22sHntJ4Ub+9k34XQCX+oHt2A==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-x64-musl": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-musl/-/watcher-linux-x64-musl-2.5.1.tgz", + "integrity": "sha512-n0E2EQbatQ3bXhcH2D1XIAANAcTZkQICBPVaxMeaCVBtOpBZpWJuf7LwyWPSBDITb7In8mqQgJ7gH8CILCURXg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-win32-arm64": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-arm64/-/watcher-win32-arm64-2.5.1.tgz", + "integrity": "sha512-RFzklRvmc3PkjKjry3hLF9wD7ppR4AKcWNzH7kXR7GUe0Igb3Nz8fyPwtZCSquGrhU5HhUNDr/mKBqj7tqA2Vw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-win32-ia32": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-ia32/-/watcher-win32-ia32-2.5.1.tgz", + "integrity": "sha512-c2KkcVN+NJmuA7CGlaGD1qJh1cLfDnQsHjE89E60vUEMlqduHGCdCLJCID5geFVM0dOtA3ZiIO8BoEQmzQVfpQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-win32-x64": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-x64/-/watcher-win32-x64-2.5.1.tgz", + "integrity": "sha512-9lHBdJITeNR++EvSQVUcaZoWupyHfXe1jZvGZ06O/5MflPcuPLtEphScIBL+AiCWBO46tDSHzWyD0uDmmZqsgA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/workers": { + "version": "2.13.3", + "resolved": "https://registry.npmjs.org/@parcel/workers/-/workers-2.13.3.tgz", + "integrity": "sha512-oAHmdniWTRwwwsKbcF4t3VjOtKN+/W17Wj5laiYB+HLkfsjGTfIQPj3sdXmrlBAGpI4omIcvR70PHHXnfdTfwA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@parcel/diagnostic": "2.13.3", + "@parcel/logger": "2.13.3", + "@parcel/profiler": "2.13.3", + "@parcel/types-internal": "2.13.3", + "@parcel/utils": "2.13.3", + "nullthrows": "^1.1.1" + }, + "engines": { + "node": ">= 16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + }, + "peerDependencies": { + "@parcel/core": "^2.13.3" + } + }, + "node_modules/@swc/core": { + "version": "1.10.12", + "resolved": "https://registry.npmjs.org/@swc/core/-/core-1.10.12.tgz", + "integrity": "sha512-+iUL0PYpPm6N9AdV1wvafakvCqFegQus1aoEDxgFsv3/uNVNIyRaupf/v/Zkp5hbep2EzhtoJR0aiJIzDbXWHg==", + "dev": true, + "hasInstallScript": true, + "license": "Apache-2.0", + "dependencies": { + "@swc/counter": "^0.1.3", + "@swc/types": "^0.1.17" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/swc" + }, + "optionalDependencies": { + "@swc/core-darwin-arm64": "1.10.12", + "@swc/core-darwin-x64": "1.10.12", + "@swc/core-linux-arm-gnueabihf": "1.10.12", + "@swc/core-linux-arm64-gnu": "1.10.12", + "@swc/core-linux-arm64-musl": "1.10.12", + "@swc/core-linux-x64-gnu": "1.10.12", + "@swc/core-linux-x64-musl": "1.10.12", + "@swc/core-win32-arm64-msvc": "1.10.12", + "@swc/core-win32-ia32-msvc": "1.10.12", + "@swc/core-win32-x64-msvc": "1.10.12" + }, + "peerDependencies": { + "@swc/helpers": "*" + }, + "peerDependenciesMeta": { + "@swc/helpers": { + "optional": true + } + } + }, + "node_modules/@swc/core-darwin-arm64": { + "version": "1.10.12", + "resolved": "https://registry.npmjs.org/@swc/core-darwin-arm64/-/core-darwin-arm64-1.10.12.tgz", + "integrity": "sha512-pOANQegUTAriW7jq3SSMZGM5l89yLVMs48R0F2UG6UZsH04SiViCnDctOGlA/Sa++25C+rL9MGMYM1jDLylBbg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0 AND MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-darwin-x64": { + "version": "1.10.12", + "resolved": "https://registry.npmjs.org/@swc/core-darwin-x64/-/core-darwin-x64-1.10.12.tgz", + "integrity": "sha512-m4kbpIDDsN1FrwfNQMU+FTrss356xsXvatLbearwR+V0lqOkjLBP0VmRvQfHEg+uy13VPyrT9gj4HLoztlci7w==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0 AND MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-linux-arm-gnueabihf": { + "version": "1.10.12", + "resolved": "https://registry.npmjs.org/@swc/core-linux-arm-gnueabihf/-/core-linux-arm-gnueabihf-1.10.12.tgz", + "integrity": "sha512-OY9LcupgqEu8zVK+rJPes6LDJJwPDmwaShU96beTaxX2K6VrXbpwm5WbPS/8FfQTsmpnuA7dCcMPUKhNgmzTrQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-linux-arm64-gnu": { + "version": "1.10.12", + "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-gnu/-/core-linux-arm64-gnu-1.10.12.tgz", + "integrity": "sha512-nJD587rO0N4y4VZszz3xzVr7JIiCzSMhEMWnPjuh+xmPxDBz0Qccpr8xCr1cSxpl1uY7ERkqAGlKr6CwoV5kVg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0 AND MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-linux-arm64-musl": { + "version": "1.10.12", + "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-musl/-/core-linux-arm64-musl-1.10.12.tgz", + "integrity": "sha512-oqhSmV+XauSf0C//MoQnVErNUB/5OzmSiUzuazyLsD5pwqKNN+leC3JtRQ/QVzaCpr65jv9bKexT9+I2Tt3xDw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0 AND MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-linux-x64-gnu": { + "version": "1.10.12", + "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.10.12.tgz", + "integrity": "sha512-XldSIHyjD7m1Gh+/8rxV3Ok711ENLI420CU2EGEqSe3VSGZ7pHJvJn9ZFbYpWhsLxPqBYMFjp3Qw+J6OXCPXCA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0 AND MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-linux-x64-musl": { + "version": "1.10.12", + "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-musl/-/core-linux-x64-musl-1.10.12.tgz", + "integrity": "sha512-wvPXzJxzPgTqhyp1UskOx1hRTtdWxlyFD1cGWOxgLsMik0V9xKRgqKnMPv16Nk7L9xl6quQ6DuUHj9ID7L3oVw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0 AND MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-win32-arm64-msvc": { + "version": "1.10.12", + "resolved": "https://registry.npmjs.org/@swc/core-win32-arm64-msvc/-/core-win32-arm64-msvc-1.10.12.tgz", + "integrity": "sha512-TUYzWuu1O7uyIcRfxdm6Wh1u+gNnrW5M1DUgDOGZLsyQzgc2Zjwfh2llLhuAIilvCVg5QiGbJlpibRYJ/8QGsg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0 AND MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-win32-ia32-msvc": { + "version": "1.10.12", + "resolved": "https://registry.npmjs.org/@swc/core-win32-ia32-msvc/-/core-win32-ia32-msvc-1.10.12.tgz", + "integrity": "sha512-4Qrw+0Xt+Fe2rz4OJ/dEPMeUf/rtuFWWAj/e0vL7J5laUHirzxawLRE5DCJLQTarOiYR6mWnmadt9o3EKzV6Xg==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "Apache-2.0 AND MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-win32-x64-msvc": { + "version": "1.10.12", + "resolved": "https://registry.npmjs.org/@swc/core-win32-x64-msvc/-/core-win32-x64-msvc-1.10.12.tgz", + "integrity": "sha512-YiloZXLW7rUxJpALwHXaGjVaAEn+ChoblG7/3esque+Y7QCyheoBUJp2DVM1EeVA43jBfZ8tvYF0liWd9Tpz1A==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0 AND MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/counter": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/@swc/counter/-/counter-0.1.3.tgz", + "integrity": "sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ==", + "dev": true, + "license": "Apache-2.0" + }, + "node_modules/@swc/helpers": { + "version": "0.5.15", + "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.15.tgz", + "integrity": "sha512-JQ5TuMi45Owi4/BIMAJBoSQoOJu12oOk/gADqlcUL9JEdHB8vyjUSsxqeNXnmXHjYKMi2WcYtezGEEhqUI/E2g==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.8.0" + } + }, + "node_modules/@swc/types": { + "version": "0.1.17", + "resolved": "https://registry.npmjs.org/@swc/types/-/types-0.1.17.tgz", + "integrity": "sha512-V5gRru+aD8YVyCOMAjMpWR1Ui577DD5KSJsHP8RAxopAH22jFz6GZd/qxqjO6MJHQhcsjvjOFXyDhyLQUnMveQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@swc/counter": "^0.1.3" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true, + "license": "Python-2.0" + }, + "node_modules/base-x": { + "version": "3.0.10", + "resolved": "https://registry.npmjs.org/base-x/-/base-x-3.0.10.tgz", + "integrity": "sha512-7d0s06rR9rYaIWHkpfLIFICM/tkSVdoPC9qYAQRpxn9DdKNWNsKC0uk++akckyLq16Tx2WIinnZ6WRriAt6njQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "safe-buffer": "^5.0.1" + } + }, + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "dev": true, + "license": "MIT", + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/browserslist": { + "version": "4.24.4", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.24.4.tgz", + "integrity": "sha512-KDi1Ny1gSePi1vm0q4oxSF8b4DR44GF4BbmS2YdhPLOEqd8pDviZOGH/GsmRwoWJ2+5Lr085X7naowMwKHDG1A==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "caniuse-lite": "^1.0.30001688", + "electron-to-chromium": "^1.5.73", + "node-releases": "^2.0.19", + "update-browserslist-db": "^1.1.1" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001696", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001696.tgz", + "integrity": "sha512-pDCPkvzfa39ehJtJ+OwGT/2yvT2SbjfHhiIW2LWOAcMQ7BzwxT/XuyUp4OTOd0XFWA6BKw0JalnBHgSi5DGJBQ==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "CC-BY-4.0" + }, + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/chrome-trace-event": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.4.tgz", + "integrity": "sha512-rNjApaLzuwaOTjCiT8lSDdGN1APCiqkChLMJxJPWLunPAt5fy8xgU9/jNOchV84wfIxrA0lRQB7oCT8jrn/wrQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.0" + } + }, + "node_modules/clone": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/clone/-/clone-2.1.2.tgz", + "integrity": "sha512-3Pe/CF1Nn94hyhIYpjtiLhdCoEoz0DqQ+988E9gmeEdQZlojxnOb74wctFyuwWQHzqyf9X7C7MG8juUpqBJT8w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true, + "license": "MIT" + }, + "node_modules/commander": { + "version": "12.1.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-12.1.0.tgz", + "integrity": "sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/cosmiconfig": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-9.0.0.tgz", + "integrity": "sha512-itvL5h8RETACmOTFc4UfIyB2RfEHi71Ax6E/PivVxq9NseKbOWpeyHEOIbmAw1rs8Ak0VursQNww7lf7YtUwzg==", + "dev": true, + "license": "MIT", + "dependencies": { + "env-paths": "^2.2.1", + "import-fresh": "^3.3.0", + "js-yaml": "^4.1.0", + "parse-json": "^5.2.0" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/d-fischer" + }, + "peerDependencies": { + "typescript": ">=4.9.5" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/detect-libc": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz", + "integrity": "sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "detect-libc": "bin/detect-libc.js" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/dom-serializer": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz", + "integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==", + "dev": true, + "license": "MIT", + "dependencies": { + "domelementtype": "^2.3.0", + "domhandler": "^5.0.2", + "entities": "^4.2.0" + }, + "funding": { + "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" + } + }, + "node_modules/domelementtype": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", + "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ], + "license": "BSD-2-Clause" + }, + "node_modules/domhandler": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz", + "integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "domelementtype": "^2.3.0" + }, + "engines": { + "node": ">= 4" + }, + "funding": { + "url": "https://github.com/fb55/domhandler?sponsor=1" + } + }, + "node_modules/domutils": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.2.2.tgz", + "integrity": "sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "dom-serializer": "^2.0.0", + "domelementtype": "^2.3.0", + "domhandler": "^5.0.3" + }, + "funding": { + "url": "https://github.com/fb55/domutils?sponsor=1" + } + }, + "node_modules/dotenv": { + "version": "16.4.7", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.4.7.tgz", + "integrity": "sha512-47qPchRCykZC03FhkYAhrvwU4xDBFIj1QPqaarj6mdM/hgUzfPHcpkHJOn3mJAufFeeAxAzeGsr5X0M4k6fLZQ==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://dotenvx.com" + } + }, + "node_modules/dotenv-expand": { + "version": "11.0.7", + "resolved": "https://registry.npmjs.org/dotenv-expand/-/dotenv-expand-11.0.7.tgz", + "integrity": "sha512-zIHwmZPRshsCdpMDyVsqGmgyP0yT8GAgXUnkdAoJisxvf33k7yO6OuoKmcTGuXPWSsm8Oh88nZicRLA9Y0rUeA==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "dotenv": "^16.4.5" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://dotenvx.com" + } + }, + "node_modules/electron-to-chromium": { + "version": "1.5.90", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.90.tgz", + "integrity": "sha512-C3PN4aydfW91Natdyd449Kw+BzhLmof6tzy5W1pFC5SpQxVXT+oyiyOG9AgYYSN9OdA/ik3YkCrpwqI8ug5Tug==", + "dev": true, + "license": "ISC" + }, + "node_modules/entities": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", + "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/env-paths": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz", + "integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-arrayish": "^0.2.1" + } + }, + "node_modules/escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "dev": true, + "license": "MIT", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/get-port": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/get-port/-/get-port-4.2.0.tgz", + "integrity": "sha512-/b3jarXkH8KJoOMQc3uVGHASwGLPq3gSFJ7tgJm2diza+bydJPTGOibin2steecKeOylE8oY2JERlVWkAJO6yw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/globals": { + "version": "13.24.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", + "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "type-fest": "^0.20.2" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/htmlnano": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/htmlnano/-/htmlnano-2.1.1.tgz", + "integrity": "sha512-kAERyg/LuNZYmdqgCdYvugyLWNFAm8MWXpQMz1pLpetmCbFwoMxvkSoaAMlFrOC4OKTWI4KlZGT/RsNxg4ghOw==", + "dev": true, + "license": "MIT", + "dependencies": { + "cosmiconfig": "^9.0.0", + "posthtml": "^0.16.5", + "timsort": "^0.3.0" + }, + "peerDependencies": { + "cssnano": "^7.0.0", + "postcss": "^8.3.11", + "purgecss": "^6.0.0", + "relateurl": "^0.2.7", + "srcset": "5.0.1", + "svgo": "^3.0.2", + "terser": "^5.10.0", + "uncss": "^0.17.3" + }, + "peerDependenciesMeta": { + "cssnano": { + "optional": true + }, + "postcss": { + "optional": true + }, + "purgecss": { + "optional": true + }, + "relateurl": { + "optional": true + }, + "srcset": { + "optional": true + }, + "svgo": { + "optional": true + }, + "terser": { + "optional": true + }, + "uncss": { + "optional": true + } + } + }, + "node_modules/htmlparser2": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-9.1.0.tgz", + "integrity": "sha512-5zfg6mHUoaer/97TxnGpxmbR7zJtPwIYFMZ/H5ucTlPZhKvtum05yiPK3Mgai3a0DyVxv7qYqoweaEd2nrYQzQ==", + "dev": true, + "funding": [ + "https://github.com/fb55/htmlparser2?sponsor=1", + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ], + "license": "MIT", + "dependencies": { + "domelementtype": "^2.3.0", + "domhandler": "^5.0.3", + "domutils": "^3.1.0", + "entities": "^4.5.0" + } + }, + "node_modules/import-fresh": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "dev": true, + "license": "MIT", + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", + "dev": true, + "license": "MIT" + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-json": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-json/-/is-json-2.0.1.tgz", + "integrity": "sha512-6BEnpVn1rcf3ngfmViLM6vjUjGErbdrL4rwlv+u1NO1XO8kqT4YGL8+19Q+Z/bas8tY90BTWMk2+fW1g6hQjbA==", + "dev": true, + "license": "ISC" + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", + "dev": true, + "license": "MIT" + }, + "node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "dev": true, + "license": "MIT", + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/lightningcss": { + "version": "1.29.1", + "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.29.1.tgz", + "integrity": "sha512-FmGoeD4S05ewj+AkhTY+D+myDvXI6eL27FjHIjoyUkO/uw7WZD1fBVs0QxeYWa7E17CUHJaYX/RUGISCtcrG4Q==", + "dev": true, + "license": "MPL-2.0", + "dependencies": { + "detect-libc": "^1.0.3" + }, + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + }, + "optionalDependencies": { + "lightningcss-darwin-arm64": "1.29.1", + "lightningcss-darwin-x64": "1.29.1", + "lightningcss-freebsd-x64": "1.29.1", + "lightningcss-linux-arm-gnueabihf": "1.29.1", + "lightningcss-linux-arm64-gnu": "1.29.1", + "lightningcss-linux-arm64-musl": "1.29.1", + "lightningcss-linux-x64-gnu": "1.29.1", + "lightningcss-linux-x64-musl": "1.29.1", + "lightningcss-win32-arm64-msvc": "1.29.1", + "lightningcss-win32-x64-msvc": "1.29.1" + } + }, + "node_modules/lightningcss-darwin-arm64": { + "version": "1.29.1", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.29.1.tgz", + "integrity": "sha512-HtR5XJ5A0lvCqYAoSv2QdZZyoHNttBpa5EP9aNuzBQeKGfbyH5+UipLWvVzpP4Uml5ej4BYs5I9Lco9u1fECqw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-darwin-x64": { + "version": "1.29.1", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.29.1.tgz", + "integrity": "sha512-k33G9IzKUpHy/J/3+9MCO4e+PzaFblsgBjSGlpAaFikeBFm8B/CkO3cKU9oI4g+fjS2KlkLM/Bza9K/aw8wsNA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-freebsd-x64": { + "version": "1.29.1", + "resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.29.1.tgz", + "integrity": "sha512-0SUW22fv/8kln2LnIdOCmSuXnxgxVC276W5KLTwoehiO0hxkacBxjHOL5EtHD8BAXg2BvuhsJPmVMasvby3LiQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm-gnueabihf": { + "version": "1.29.1", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.29.1.tgz", + "integrity": "sha512-sD32pFvlR0kDlqsOZmYqH/68SqUMPNj+0pucGxToXZi4XZgZmqeX/NkxNKCPsswAXU3UeYgDSpGhu05eAufjDg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm64-gnu": { + "version": "1.29.1", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.29.1.tgz", + "integrity": "sha512-0+vClRIZ6mmJl/dxGuRsE197o1HDEeeRk6nzycSy2GofC2JsY4ifCRnvUWf/CUBQmlrvMzt6SMQNMSEu22csWQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm64-musl": { + "version": "1.29.1", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.29.1.tgz", + "integrity": "sha512-UKMFrG4rL/uHNgelBsDwJcBqVpzNJbzsKkbI3Ja5fg00sgQnHw/VrzUTEc4jhZ+AN2BvQYz/tkHu4vt1kLuJyw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-x64-gnu": { + "version": "1.29.1", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.29.1.tgz", + "integrity": "sha512-u1S+xdODy/eEtjADqirA774y3jLcm8RPtYztwReEXoZKdzgsHYPl0s5V52Tst+GKzqjebkULT86XMSxejzfISw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-x64-musl": { + "version": "1.29.1", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.29.1.tgz", + "integrity": "sha512-L0Tx0DtaNUTzXv0lbGCLB/c/qEADanHbu4QdcNOXLIe1i8i22rZRpbT3gpWYsCh9aSL9zFujY/WmEXIatWvXbw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-win32-arm64-msvc": { + "version": "1.29.1", + "resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.29.1.tgz", + "integrity": "sha512-QoOVnkIEFfbW4xPi+dpdft/zAKmgLgsRHfJalEPYuJDOWf7cLQzYg0DEh8/sn737FaeMJxHZRc1oBreiwZCjog==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-win32-x64-msvc": { + "version": "1.29.1", + "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.29.1.tgz", + "integrity": "sha512-NygcbThNBe4JElP+olyTI/doBNGJvLs3bFCRPdvuCcxZCcCZ71B858IHpdm7L1btZex0FvCmM17FK98Y9MRy1Q==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", + "dev": true, + "license": "MIT" + }, + "node_modules/lmdb": { + "version": "2.8.5", + "resolved": "https://registry.npmjs.org/lmdb/-/lmdb-2.8.5.tgz", + "integrity": "sha512-9bMdFfc80S+vSldBmG3HOuLVHnxRdNTlpzR6QDnzqCQtCzGUEAGTzBKYMeIM+I/sU4oZfgbcbS7X7F65/z/oxQ==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "dependencies": { + "msgpackr": "^1.9.5", + "node-addon-api": "^6.1.0", + "node-gyp-build-optional-packages": "5.1.1", + "ordered-binary": "^1.4.1", + "weak-lru-cache": "^1.2.2" + }, + "bin": { + "download-lmdb-prebuilds": "bin/download-prebuilds.js" + }, + "optionalDependencies": { + "@lmdb/lmdb-darwin-arm64": "2.8.5", + "@lmdb/lmdb-darwin-x64": "2.8.5", + "@lmdb/lmdb-linux-arm": "2.8.5", + "@lmdb/lmdb-linux-arm64": "2.8.5", + "@lmdb/lmdb-linux-x64": "2.8.5", + "@lmdb/lmdb-win32-x64": "2.8.5" + } + }, + "node_modules/lmdb/node_modules/node-addon-api": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-6.1.0.tgz", + "integrity": "sha512-+eawOlIgy680F0kBzPUNFhMZGtJ1YmqM6l4+Crf4IkImjYrO/mqPwRMh352g23uIaQKFItcQ64I7KMaJxHgAVA==", + "dev": true, + "license": "MIT" + }, + "node_modules/micromatch": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", + "dev": true, + "license": "MIT", + "dependencies": { + "braces": "^3.0.3", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/msgpackr": { + "version": "1.11.2", + "resolved": "https://registry.npmjs.org/msgpackr/-/msgpackr-1.11.2.tgz", + "integrity": "sha512-F9UngXRlPyWCDEASDpTf6c9uNhGPTqnTeLVt7bN+bU1eajoR/8V9ys2BRaV5C/e5ihE6sJ9uPIKaYt6bFuO32g==", + "dev": true, + "license": "MIT", + "optionalDependencies": { + "msgpackr-extract": "^3.0.2" + } + }, + "node_modules/msgpackr-extract": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/msgpackr-extract/-/msgpackr-extract-3.0.3.tgz", + "integrity": "sha512-P0efT1C9jIdVRefqjzOQ9Xml57zpOXnIuS+csaB4MdZbTdmGDLo8XhzBG1N7aO11gKDDkJvBLULeFTo46wwreA==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "dependencies": { + "node-gyp-build-optional-packages": "5.2.2" + }, + "bin": { + "download-msgpackr-prebuilds": "bin/download-prebuilds.js" + }, + "optionalDependencies": { + "@msgpackr-extract/msgpackr-extract-darwin-arm64": "3.0.3", + "@msgpackr-extract/msgpackr-extract-darwin-x64": "3.0.3", + "@msgpackr-extract/msgpackr-extract-linux-arm": "3.0.3", + "@msgpackr-extract/msgpackr-extract-linux-arm64": "3.0.3", + "@msgpackr-extract/msgpackr-extract-linux-x64": "3.0.3", + "@msgpackr-extract/msgpackr-extract-win32-x64": "3.0.3" + } + }, + "node_modules/msgpackr-extract/node_modules/detect-libc": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.3.tgz", + "integrity": "sha512-bwy0MGW55bG41VqxxypOsdSdGqLwXPI/focwgTYCFMbdUiBAxLg9CFzG08sz2aqzknwiX7Hkl0bQENjg8iLByw==", + "dev": true, + "license": "Apache-2.0", + "optional": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/msgpackr-extract/node_modules/node-gyp-build-optional-packages": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/node-gyp-build-optional-packages/-/node-gyp-build-optional-packages-5.2.2.tgz", + "integrity": "sha512-s+w+rBWnpTMwSFbaE0UXsRlg7hU4FjekKU4eyAih5T8nJuNZT1nNsskXpxmeqSK9UzkBl6UgRlnKc8hz8IEqOw==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "detect-libc": "^2.0.1" + }, + "bin": { + "node-gyp-build-optional-packages": "bin.js", + "node-gyp-build-optional-packages-optional": "optional.js", + "node-gyp-build-optional-packages-test": "build-test.js" + } + }, + "node_modules/node-addon-api": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-7.1.1.tgz", + "integrity": "sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/node-gyp-build-optional-packages": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/node-gyp-build-optional-packages/-/node-gyp-build-optional-packages-5.1.1.tgz", + "integrity": "sha512-+P72GAjVAbTxjjwUmwjVrqrdZROD4nf8KgpBoDxqXXTiYZZt/ud60dE5yvCSr9lRO8e8yv6kgJIC0K0PfZFVQw==", + "dev": true, + "license": "MIT", + "dependencies": { + "detect-libc": "^2.0.1" + }, + "bin": { + "node-gyp-build-optional-packages": "bin.js", + "node-gyp-build-optional-packages-optional": "optional.js", + "node-gyp-build-optional-packages-test": "build-test.js" + } + }, + "node_modules/node-gyp-build-optional-packages/node_modules/detect-libc": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.3.tgz", + "integrity": "sha512-bwy0MGW55bG41VqxxypOsdSdGqLwXPI/focwgTYCFMbdUiBAxLg9CFzG08sz2aqzknwiX7Hkl0bQENjg8iLByw==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=8" + } + }, + "node_modules/node-releases": { + "version": "2.0.19", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.19.tgz", + "integrity": "sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw==", + "dev": true, + "license": "MIT" + }, + "node_modules/nullthrows": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/nullthrows/-/nullthrows-1.1.1.tgz", + "integrity": "sha512-2vPPEi+Z7WqML2jZYddDIfy5Dqb0r2fze2zTxNNknZaFpVHU3mFB3R+DWeJWGVx0ecvttSGlJTI+WG+8Z4cDWw==", + "dev": true, + "license": "MIT" + }, + "node_modules/ordered-binary": { + "version": "1.5.3", + "resolved": "https://registry.npmjs.org/ordered-binary/-/ordered-binary-1.5.3.tgz", + "integrity": "sha512-oGFr3T+pYdTGJ+YFEILMpS3es+GiIbs9h/XQrclBXUtd44ey7XwfsMzM31f64I1SQOawDoDr/D823kNCADI8TA==", + "dev": true, + "license": "MIT" + }, + "node_modules/parcel": { + "version": "2.13.3", + "resolved": "https://registry.npmjs.org/parcel/-/parcel-2.13.3.tgz", + "integrity": "sha512-8GrC8C7J8mwRpAlk7EJ7lwdFTbCN+dcXH2gy5AsEs9pLfzo9wvxOTx6W0fzSlvCOvZOita+8GdfYlGfEt0tRgA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@parcel/config-default": "2.13.3", + "@parcel/core": "2.13.3", + "@parcel/diagnostic": "2.13.3", + "@parcel/events": "2.13.3", + "@parcel/feature-flags": "2.13.3", + "@parcel/fs": "2.13.3", + "@parcel/logger": "2.13.3", + "@parcel/package-manager": "2.13.3", + "@parcel/reporter-cli": "2.13.3", + "@parcel/reporter-dev-server": "2.13.3", + "@parcel/reporter-tracer": "2.13.3", + "@parcel/utils": "2.13.3", + "chalk": "^4.1.2", + "commander": "^12.1.0", + "get-port": "^4.2.0" + }, + "bin": { + "parcel": "lib/bin.js" + }, + "engines": { + "node": ">= 16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/parcel-reporter-static-files-copy": { + "version": "1.5.3", + "resolved": "https://registry.npmjs.org/parcel-reporter-static-files-copy/-/parcel-reporter-static-files-copy-1.5.3.tgz", + "integrity": "sha512-Ukq2SyJYn3GFIPCLamXuQ+2t+0j54llujjOUoRjtmVvfsuGnJDEpMznADeIoKuQDvy0jpxtWzWkQvxqI/j+U4A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@parcel/plugin": "^2.0.0-beta.1" + }, + "engines": { + "parcel": "^2.0.0-beta.1" + } + }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "license": "MIT", + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/parse-json": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "dev": true, + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/postcss-value-parser": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", + "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/posthtml": { + "version": "0.16.6", + "resolved": "https://registry.npmjs.org/posthtml/-/posthtml-0.16.6.tgz", + "integrity": "sha512-JcEmHlyLK/o0uGAlj65vgg+7LIms0xKXe60lcDOTU7oVX/3LuEuLwrQpW3VJ7de5TaFKiW4kWkaIpJL42FEgxQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "posthtml-parser": "^0.11.0", + "posthtml-render": "^3.0.0" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/posthtml-parser": { + "version": "0.12.1", + "resolved": "https://registry.npmjs.org/posthtml-parser/-/posthtml-parser-0.12.1.tgz", + "integrity": "sha512-rYFmsDLfYm+4Ts2Oh4DCDSZPtdC1BLnRXAobypVzX9alj28KGl65dIFtgDY9zB57D0TC4Qxqrawuq/2et1P0GA==", + "dev": true, + "license": "MIT", + "dependencies": { + "htmlparser2": "^9.0.0" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/posthtml-render": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/posthtml-render/-/posthtml-render-3.0.0.tgz", + "integrity": "sha512-z+16RoxK3fUPgwaIgH9NGnK1HKY9XIDpydky5eQGgAFVXTCSezalv9U2jQuNV+Z9qV1fDWNzldcw4eK0SSbqKA==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-json": "^2.0.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/posthtml/node_modules/dom-serializer": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.4.1.tgz", + "integrity": "sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag==", + "dev": true, + "license": "MIT", + "dependencies": { + "domelementtype": "^2.0.1", + "domhandler": "^4.2.0", + "entities": "^2.0.0" + }, + "funding": { + "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" + } + }, + "node_modules/posthtml/node_modules/dom-serializer/node_modules/entities": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz", + "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==", + "dev": true, + "license": "BSD-2-Clause", + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/posthtml/node_modules/domhandler": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.3.1.tgz", + "integrity": "sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "domelementtype": "^2.2.0" + }, + "engines": { + "node": ">= 4" + }, + "funding": { + "url": "https://github.com/fb55/domhandler?sponsor=1" + } + }, + "node_modules/posthtml/node_modules/domutils": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.8.0.tgz", + "integrity": "sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "dom-serializer": "^1.0.1", + "domelementtype": "^2.2.0", + "domhandler": "^4.2.0" + }, + "funding": { + "url": "https://github.com/fb55/domutils?sponsor=1" + } + }, + "node_modules/posthtml/node_modules/entities": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/entities/-/entities-3.0.1.tgz", + "integrity": "sha512-WiyBqoomrwMdFG1e0kqvASYfnlb0lp8M5o5Fw2OFq1hNZxxcNk8Ik0Xm7LxzBhuidnZB/UtBqVCgUz3kBOP51Q==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/posthtml/node_modules/htmlparser2": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-7.2.0.tgz", + "integrity": "sha512-H7MImA4MS6cw7nbyURtLPO1Tms7C5H602LRETv95z1MxO/7CP7rDVROehUYeYBUYEON94NXXDEPmZuq+hX4sog==", + "dev": true, + "funding": [ + "https://github.com/fb55/htmlparser2?sponsor=1", + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ], + "license": "MIT", + "dependencies": { + "domelementtype": "^2.0.1", + "domhandler": "^4.2.2", + "domutils": "^2.8.0", + "entities": "^3.0.1" + } + }, + "node_modules/posthtml/node_modules/posthtml-parser": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/posthtml-parser/-/posthtml-parser-0.11.0.tgz", + "integrity": "sha512-QecJtfLekJbWVo/dMAA+OSwY79wpRmbqS5TeXvXSX+f0c6pW4/SE6inzZ2qkU7oAMCPqIDkZDvd/bQsSFUnKyw==", + "dev": true, + "license": "MIT", + "dependencies": { + "htmlparser2": "^7.1.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/react-error-overlay": { + "version": "6.0.9", + "resolved": "https://registry.npmjs.org/react-error-overlay/-/react-error-overlay-6.0.9.tgz", + "integrity": "sha512-nQTTcUu+ATDbrSD1BZHr5kgSD4oF8OFjxun8uAaL8RwPBacGBNPf/yAuVVdx17N8XNzRDMrZ9XcKZHCjPW+9ew==", + "dev": true, + "license": "MIT" + }, + "node_modules/react-refresh": { + "version": "0.14.2", + "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.14.2.tgz", + "integrity": "sha512-jCvmsr+1IUSMUyzOkRcvnVbX3ZYC6g9TDrDbFuFmRDq7PD4yaGbLKNQL6k2jnArV8hjYxh7hVhAZB6s9HDGpZA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/regenerator-runtime": { + "version": "0.14.1", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz", + "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==", + "dev": true, + "license": "MIT" + }, + "node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/semver": { + "version": "7.7.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.0.tgz", + "integrity": "sha512-DrfFnPzblFmNrIZzg5RzHegbiRWg7KMR7btwi2yjHwx06zsUbO5g613sVwEV7FTwmzJu+Io0lJe2GJ3LxqpvBQ==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/srcset": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/srcset/-/srcset-5.0.1.tgz", + "integrity": "sha512-/P1UYbGfJVlxZag7aABNRrulEXAwCSDo7fklafOQrantuPTDmYgijJMks2zusPCVzgW9+4P69mq7w6pYuZpgxw==", + "dev": true, + "license": "MIT", + "optional": true, + "peer": true, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/term-size": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/term-size/-/term-size-2.2.1.tgz", + "integrity": "sha512-wK0Ri4fOGjv/XPy8SBHZChl8CM7uMc5VML7SqiQ0zG7+J5Vr+RMQDoHa2CNT6KHUnTGIXH34UDMkPzAUyapBZg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/timsort": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/timsort/-/timsort-0.3.0.tgz", + "integrity": "sha512-qsdtZH+vMoCARQtyod4imc2nIJwg9Cc7lPRrw9CzF8ZKR0khdr8+2nX80PBhET3tcyTtJDxAffGh2rXH4tyU8A==", + "dev": true, + "license": "MIT" + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "dev": true, + "license": "0BSD" + }, + "node_modules/type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "dev": true, + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/update-browserslist-db": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.2.tgz", + "integrity": "sha512-PPypAm5qvlD7XMZC3BujecnaOxwhrtoFR+Dqkk5Aa/6DssiH0ibKoketaj9w8LP7Bont1rYeoV5plxD7RTEPRg==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "escalade": "^3.2.0", + "picocolors": "^1.1.1" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, + "node_modules/utility-types": { + "version": "3.11.0", + "resolved": "https://registry.npmjs.org/utility-types/-/utility-types-3.11.0.tgz", + "integrity": "sha512-6Z7Ma2aVEWisaL6TvBCy7P8rm2LQoPv6dJ7ecIaIixHcwfbJ0x7mWdbcwlIM5IGQxPZSFYeqRCqlOOeKoJYMkw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/weak-lru-cache": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/weak-lru-cache/-/weak-lru-cache-1.2.2.tgz", + "integrity": "sha512-DEAoo25RfSYMuTGc9vPJzZcZullwIqRDSI9LOy+fkCJPi6hykCnfKaXTuPBDuXAUcqHXyOgFtHNp/kB2FjYHbw==", + "dev": true, + "license": "MIT" + } + } +} diff --git a/package.json b/package.json index a8e13a48..6ff84628 100644 --- a/package.json +++ b/package.json @@ -2,10 +2,9 @@ "name": "javascript-snake", "version": "1.0.0", "description": "JavaScript Snake
By Patrick Gillespie
License: MIT
http://patorjk.com/games/snake", - "main": "index.html", "scripts": { - "start": "parcel index.html --open", - "build": "parcel build index.html", + "start": "parcel src/index.html --open", + "build": "parcel build src/index.html", "test": "echo \"Error: no test specified\" && exit 1" }, "repository": { @@ -18,8 +17,12 @@ "url": "https://github.com/patorjk/JavaScript-Snake/issues" }, "homepage": "https://github.com/patorjk/JavaScript-Snake#readme", - "dependencies": {}, "devDependencies": { - "parcel-bundler": "^1.6.1" + "parcel": "^2.13.3", + "parcel-reporter-static-files-copy": "^1.5.3" + }, + "staticFiles": { + "staticPath": "src/css", + "staticOutPath": "css" } } diff --git a/css/Senura-snake.css b/src/css/Senura-snake.css similarity index 94% rename from css/Senura-snake.css rename to src/css/Senura-snake.css index 180ea4a3..15ac9b61 100644 --- a/css/Senura-snake.css +++ b/src/css/Senura-snake.css @@ -72,10 +72,10 @@ a.snake-link:hover { } .snake-snakebody-alive { - background-image: url('./images/dark-snakeblock.png'); + background-image: url('src/css/images/dark-snakeblock.png'); } .snake-snakebody-dead { - background-image: url('./images/dead-dark-snakeblock.png'); + background-image: url('src/css/images/dead-dark-snakeblock.png'); } .snake-food-block { diff --git a/css/black-snake.css b/src/css/black-snake.css similarity index 92% rename from css/black-snake.css rename to src/css/black-snake.css index 0c460b7c..90d22abf 100644 --- a/css/black-snake.css +++ b/src/css/black-snake.css @@ -68,10 +68,10 @@ a.snake-link:hover { } .snake-snakebody-alive { - background-image: url('./css/images/snakeblock.png'), url('./images/snakeblock.png'); + background-image: url('src/cssss/images/snakeblock.png'), url('src/css/images/snakeblock.png'); } .snake-snakebody-dead { - background-image: url('./css/images/deadblock.png'), url('./images/deadblock.png'); + background-image: url('src/cssss/images/deadblock.png'), url('src/css/images/deadblock.png'); } .snake-food-block { diff --git a/css/dark-snake.css b/src/css/dark-snake.css similarity index 94% rename from css/dark-snake.css rename to src/css/dark-snake.css index ab8728d4..8603a1cb 100644 --- a/css/dark-snake.css +++ b/src/css/dark-snake.css @@ -72,10 +72,10 @@ a.snake-link:hover { } .snake-snakebody-alive { - background-image: url('./images/dark-snakeblock.png'); + background-image: url('src/css/images/dark-snakeblock.png'); } .snake-snakebody-dead { - background-image: url('./images/dead-dark-snakeblock.png'); + background-image: url('src/css/images/dead-dark-snakeblock.png'); } .snake-food-block { diff --git a/css/green-snake.css b/src/css/green-snake.css similarity index 95% rename from css/green-snake.css rename to src/css/green-snake.css index 17a347a3..64cf1564 100644 --- a/css/green-snake.css +++ b/src/css/green-snake.css @@ -74,10 +74,10 @@ a.snake-link:hover { } .snake-snakebody-alive { - background-image: url('./images/snakeblock.png'); + background-image: url('src/css/images/snakeblock.png'); } .snake-snakebody-dead { - background-image: url('./images/deadblock.png'); + background-image: url('src/css/images/deadblock.png'); } .snake-food-block { diff --git a/css/head-snake.css b/src/css/head-snake.css similarity index 90% rename from css/head-snake.css rename to src/css/head-snake.css index dc05c8f2..e077a44a 100644 --- a/css/head-snake.css +++ b/src/css/head-snake.css @@ -53,7 +53,7 @@ a.snake-link:hover { } #snake-snakehead-alive { - background-image: url('./images/green-head-snakeblock.png'); + background-image: url('src/css/images/green-head-snakeblock.png'); margin: 0px; padding: 0px; background-color: rgb(10, 173, 10); @@ -73,10 +73,10 @@ a.snake-link:hover { } .snake-snakebody-alive { - background-image: url('./images/green-body-snakeblock.png'), url('./images/green-body-snakeblock.png'); + background-image: url('src/css/images/green-body-snakeblock.png'), url('src/css/images/green-body-snakeblock.png'); } .snake-snakebody-dead { - background-image: url('./images/deadblock.png'), url('./images/deadblock.png'); + background-image: url('src/css/images/deadblock.png'), url('src/css/images/deadblock.png'); } .snake-food-block { diff --git a/css/images/Thumbs.db b/src/css/images/Thumbs.db similarity index 100% rename from css/images/Thumbs.db rename to src/css/images/Thumbs.db diff --git a/css/images/dark-snakeblock.png b/src/css/images/dark-snakeblock.png similarity index 100% rename from css/images/dark-snakeblock.png rename to src/css/images/dark-snakeblock.png diff --git a/css/images/dead-dark-snakeblock.png b/src/css/images/dead-dark-snakeblock.png similarity index 100% rename from css/images/dead-dark-snakeblock.png rename to src/css/images/dead-dark-snakeblock.png diff --git a/css/images/deadblock.png b/src/css/images/deadblock.png similarity index 100% rename from css/images/deadblock.png rename to src/css/images/deadblock.png diff --git a/css/images/deadblock_border.png b/src/css/images/deadblock_border.png similarity index 100% rename from css/images/deadblock_border.png rename to src/css/images/deadblock_border.png diff --git a/css/images/favicon.png b/src/css/images/favicon.png similarity index 100% rename from css/images/favicon.png rename to src/css/images/favicon.png diff --git a/css/images/green-body-snakeblock.png b/src/css/images/green-body-snakeblock.png similarity index 100% rename from css/images/green-body-snakeblock.png rename to src/css/images/green-body-snakeblock.png diff --git a/css/images/green-head-snakeblock.png b/src/css/images/green-head-snakeblock.png similarity index 100% rename from css/images/green-head-snakeblock.png rename to src/css/images/green-head-snakeblock.png diff --git a/css/images/matrix-food-block.png b/src/css/images/matrix-food-block.png similarity index 100% rename from css/images/matrix-food-block.png rename to src/css/images/matrix-food-block.png diff --git a/css/images/matrix-snake-block.png b/src/css/images/matrix-snake-block.png similarity index 100% rename from css/images/matrix-snake-block.png rename to src/css/images/matrix-snake-block.png diff --git a/css/images/neon-body-snakeblock.png b/src/css/images/neon-body-snakeblock.png similarity index 100% rename from css/images/neon-body-snakeblock.png rename to src/css/images/neon-body-snakeblock.png diff --git a/css/images/neon-dead-snakeblock.png b/src/css/images/neon-dead-snakeblock.png similarity index 100% rename from css/images/neon-dead-snakeblock.png rename to src/css/images/neon-dead-snakeblock.png diff --git a/css/images/snakeblock.png b/src/css/images/snakeblock.png similarity index 100% rename from css/images/snakeblock.png rename to src/css/images/snakeblock.png diff --git a/css/light-snake.css b/src/css/light-snake.css similarity index 95% rename from css/light-snake.css rename to src/css/light-snake.css index 069cbd88..3829ee4e 100644 --- a/css/light-snake.css +++ b/src/css/light-snake.css @@ -61,10 +61,10 @@ a.snake-link:hover { background-repeat: no-repeat; } .snake-snakebody-alive { - background-image: url('./images/snakeblock.png'); + background-image: url('src/css/images/snakeblock.png'); } .snake-snakebody-dead { - background-image: url('./images/deadblock.png'); + background-image: url('src/css/images/deadblock.png'); } .snake-food-block { margin: 0px; diff --git a/css/main-snake.css b/src/css/main-snake.css similarity index 93% rename from css/main-snake.css rename to src/css/main-snake.css index 82a05adb..5623c07e 100755 --- a/css/main-snake.css +++ b/src/css/main-snake.css @@ -67,10 +67,10 @@ a.snake-link:hover { } .snake-snakebody-alive { - background-image: url('./css/images/snakeblock.png'), url('./images/snakeblock.png'); + background-image: url('./images/snakeblock.png'), url('./images/snakeblock.png'); } .snake-snakebody-dead { - background-image: url('./css/images/deadblock.png'), url('./images/deadblock.png'); + background-image: url('./images/deadblock.png'), url('./images/deadblock.png'); } .snake-food-block { diff --git a/css/matrix-snake.css b/src/css/matrix-snake.css similarity index 92% rename from css/matrix-snake.css rename to src/css/matrix-snake.css index 5c8c79ce..643d6960 100644 --- a/css/matrix-snake.css +++ b/src/css/matrix-snake.css @@ -64,10 +64,10 @@ background-repeat: no-repeat; } .snake-snakebody-alive { -background-image: url('./images/matrix-snake-block.png'); +background-image: url('src/css/images/matrix-snake-block.png'); } .snake-snakebody-dead { -background-image: url('./images/deadblock.png'); +background-image: url('src/css/images/deadblock.png'); } .snake-food-block { @@ -76,7 +76,7 @@ padding: 0px; background-color: #FF0000; border: 0px solid #000080; position: absolute; -background-image: url("./images/matrix-food-block.png") +background-image: url("src/css/images/matrix-food-block.png") } .snake-playing-field { @@ -131,4 +131,4 @@ margin-top: -75px; margin-left: -158px; text-align: center; display: none; -} \ No newline at end of file +} diff --git a/css/neon-snake.css b/src/css/neon-snake.css similarity index 86% rename from css/neon-snake.css rename to src/css/neon-snake.css index 1be055f0..31b3291f 100644 --- a/css/neon-snake.css +++ b/src/css/neon-snake.css @@ -71,10 +71,10 @@ a.snake-link:hover { } .snake-snakebody-alive { - background-image: url('./images/neon-body-snakeblock.png'), url('./css/images/neon-body-snakeblock.png'); + background-image: url('src/css/images/neon-body-snakeblock.png'), url('src/cssss/images/neon-body-snakeblock.png'); } .snake-snakebody-dead { - background-image: url('./images/neon-dead-snakeblock.png'), url('./css/images/neon-dead-snakeblock.png'); + background-image: url('src/css/images/neon-dead-snakeblock.png'), url('src/cssss/images/neon-dead-snakeblock.png'); } .snake-food-block { diff --git a/css/teal-snake.css b/src/css/teal-snake.css similarity index 95% rename from css/teal-snake.css rename to src/css/teal-snake.css index f3ad07d1..8fbe6ffa 100644 --- a/css/teal-snake.css +++ b/src/css/teal-snake.css @@ -75,10 +75,10 @@ a.snake-link:hover { } .snake-snakebody-alive { - background-image: url('./images/snakeblock.png'); + background-image: url('src/css/images/snakeblock.png'); } .snake-snakebody-dead { - background-image: url('./images/dead-dark-snakeblock.png'); + background-image: url('src/css/images/dead-dark-snakeblock.png'); } .snake-food-block { diff --git a/index.html b/src/index.html similarity index 89% rename from index.html rename to src/index.html index 172fd32b..360fe818 100755 --- a/index.html +++ b/src/index.html @@ -4,15 +4,14 @@ JavaScript Snake - + + + + + +
+
+ Theme: + +
+
+ Mode: + +
+ +
+
+ +
+ +
+ + + + + diff --git a/src/css/Senura-snake.css b/src/css/Senura-snake.css index 15ac9b61..2102a783 100644 --- a/src/css/Senura-snake.css +++ b/src/css/Senura-snake.css @@ -5,29 +5,33 @@ http://patorjk.com/games/snake */ body { - margin:0px; - padding:0px; - background-color:#000000; + margin: 0px; + padding: 0px; + background-color: #000000; } .snake-toolbar { - color: #847a87; + color: #847a87; } #game-area { - margin:10px; - padding:0px; + margin: 10px; + padding: 0px; } -#game-area:focus { outline: none; } +#game-area:focus { + outline: none; +} #mode-wrapper { - font-family: Verdana, arial, helvetica, sans-serif; - font-size: 14px; - color: #f6f0f7; + font-family: Verdana, arial, helvetica, sans-serif; + font-size: 14px; + color: #f6f0f7; } -a.snake-link, a.snake-link:link, a.snake-link:visited { +a.snake-link, +a.snake-link:link, +a.snake-link:visited { color: #605d61; } @@ -36,106 +40,107 @@ a.snake-link:hover { } .snake-pause-screen { - font-family: Verdana, arial, helvetica, sans-serif; - font-size: 14px; - position:absolute; - width:300px; - height:80px; - text-align:center; - top:50%; - left:50%; - margin-top:-40px; - margin-left:-150px; - display:none; - background-color:#ffffff; - color: #938996; + font-family: Verdana, arial, helvetica, sans-serif; + font-size: 14px; + position: absolute; + width: 300px; + height: 80px; + text-align: center; + top: 50%; + left: 50%; + margin-top: -40px; + margin-left: -150px; + display: none; + background-color: #ffffff; + color: #938996; } .snake-panel-component { - position: absolute; - font-family: Verdana, arial, helvetica, sans-serif; - font-size: 14px; - color: #cf6d6d; - text-align: center; - background-color: #550b70; - padding: 8px; - margin: 0px; + position: absolute; + font-family: Verdana, arial, helvetica, sans-serif; + font-size: 14px; + color: #cf6d6d; + text-align: center; + background-color: #550b70; + padding: 8px; + margin: 0px; } .snake-snakebody-block { - margin: 0px; - padding: 0px; - background-color: #eddff2; - position: absolute; - border: 0px solid black; - background-repeat: no-repeat; + margin: 0px; + padding: 0px; + background-color: #eddff2; + position: absolute; + border: 0px solid black; + background-repeat: no-repeat; } .snake-snakebody-alive { - background-image: url('src/css/images/dark-snakeblock.png'); + background-image: url("src/css/images/dark-snakeblock.png"); } .snake-snakebody-dead { - background-image: url('src/css/images/dead-dark-snakeblock.png'); + background-image: url("src/css/images/dead-dark-snakeblock.png"); } .snake-food-block { - margin: 0px; - padding: 0px; - background-color: black; - border: 2px solid #000000; - position: absolute; + margin: 0px; + padding: 0px; + background-color: black; + border: 2px solid #000000; + position: absolute; } .snake-playing-field { - margin: 0px; - padding: 0px; - position: absolute; - background-color: #fcfcfc; - border: 3px solid black; + margin: 0px; + padding: 0px; + position: absolute; + background-color: #fcfcfc; + border: 3px solid black; } .snake-game-container { - margin: 0px; - padding: 0px; - border-width: 0px; - border-style: none; - zoom: 1; - background-color: #3E2E44; - position: relative; + margin: 0px; + padding: 0px; + border-width: 0px; + border-style: none; + zoom: 1; + background-color: #3e2e44; + position: relative; } .snake-welcome-dialog { - padding: 8px; - margin: 0px; - background-color: black; - color: #ab00de; - font-family: Verdana, arial, helvetica, sans-serif; - font-size: 14px; - position: absolute; - top: 50%; - left: 50%; - width: 300px; - /*height: 150px;*/ - margin-top: -100px; - margin-left: -158px; - text-align: center; - display: block; -} - -.snake-try-again-dialog, .snake-win-dialog { - padding: 8px; - margin: 0px; - background-color: black; - color: #ab00de; - font-family: Verdana, arial, helvetica, sans-serif; - font-size: 14px; - position: absolute; - top: 50%; - left: 50%; - width: 300px; - height: 100px; - margin-top: -75px; - margin-left: -158px; - text-align: center; - display: none; + padding: 8px; + margin: 0px; + background-color: black; + color: #ab00de; + font-family: Verdana, arial, helvetica, sans-serif; + font-size: 14px; + position: absolute; + top: 50%; + left: 50%; + width: 300px; + /*height: 150px;*/ + margin-top: -100px; + margin-left: -158px; + text-align: center; + display: block; +} + +.snake-try-again-dialog, +.snake-win-dialog { + padding: 8px; + margin: 0px; + background-color: black; + color: #ab00de; + font-family: Verdana, arial, helvetica, sans-serif; + font-size: 14px; + position: absolute; + top: 50%; + left: 50%; + width: 300px; + height: 100px; + margin-top: -75px; + margin-left: -158px; + text-align: center; + display: none; } diff --git a/src/css/black-snake.css b/src/css/black-snake.css index 90d22abf..a92710b5 100644 --- a/src/css/black-snake.css +++ b/src/css/black-snake.css @@ -4,133 +4,139 @@ By Patrick Gillespie http://patorjk.com/games/snake */ body { - margin:0px; - padding:0px; - background-color: black; - color: white; + margin: 0px; + padding: 0px; + background-color: black; + color: white; } #game-area { - margin:10px; - padding:0px; + margin: 10px; + padding: 0px; } #mode-wrapper { - color: #ffffff; - font-family: Verdana, arial, helvetica, sans-serif; - font-size: 14px; - + color: #ffffff; + font-family: Verdana, arial, helvetica, sans-serif; + font-size: 14px; } -#game-area:focus { outline: none; } +#game-area:focus { + outline: none; +} -a.snake-link, a.snake-link:link, a.snake-link:visited { - color: #FCFC54; +a.snake-link, +a.snake-link:link, +a.snake-link:visited { + color: #fcfc54; } a.snake-link:hover { - color: #FfFf54; + color: #ffff54; } .snake-pause-screen { - font-family: Verdana, arial, helvetica, sans-serif; - font-size: 14px; - position:absolute; - width:300px; - height:80px; - text-align:center; - top:50%; - left:50%; - margin-top:-40px; - margin-left:-150px; - display:none; - background-color:black; - color:white; + font-family: Verdana, arial, helvetica, sans-serif; + font-size: 14px; + position: absolute; + width: 300px; + height: 80px; + text-align: center; + top: 50%; + left: 50%; + margin-top: -40px; + margin-left: -150px; + display: none; + background-color: black; + color: white; } .snake-panel-component { - position: absolute; - font-family: Verdana, arial, helvetica, sans-serif; - font-size: 14px; - color: #ffffff; - text-align: center; - padding: 8px; - margin: 0px; + position: absolute; + font-family: Verdana, arial, helvetica, sans-serif; + font-size: 14px; + color: #ffffff; + text-align: center; + padding: 8px; + margin: 0px; } .snake-snakebody-block { - margin: 0px; - padding: 0px; - background-color: #FF0000; - position: absolute; - border: 0px solid #000080; - background-repeat: no-repeat; + margin: 0px; + padding: 0px; + background-color: #ff0000; + position: absolute; + border: 0px solid #000080; + background-repeat: no-repeat; } .snake-snakebody-alive { - background-image: url('src/cssss/images/snakeblock.png'), url('src/css/images/snakeblock.png'); + background-image: url("src/cssss/images/snakeblock.png"), + url("src/css/images/snakeblock.png"); } .snake-snakebody-dead { - background-image: url('src/cssss/images/deadblock.png'), url('src/css/images/deadblock.png'); + background-image: url("src/cssss/images/deadblock.png"), + url("src/css/images/deadblock.png"); } .snake-food-block { - margin: 0px; - padding: 0px; - background-color: aqua; - border: 0px solid #000080; - position: absolute; + margin: 0px; + padding: 0px; + background-color: aqua; + border: 0px solid #000080; + position: absolute; } .snake-playing-field { - margin: 0px; - padding: 0px; - position: absolute; - background-color: purple; - border: 0px solid purple; + margin: 0px; + padding: 0px; + position: absolute; + background-color: purple; + border: 0px solid purple; } .snake-game-container { - margin: 0px; - padding: 0px; - border-width: 0px; - border-style: none; - zoom: 1; - position: relative; + margin: 0px; + padding: 0px; + border-width: 0px; + border-style: none; + zoom: 1; + position: relative; } .snake-welcome-dialog { - padding: 8px; - margin: 0px; - background-color: #000000; - color: #ffffff; - font-family: Verdana, arial, helvetica, sans-serif; - font-size: 14px; - position: absolute; - top: 50%; - left: 50%; - width: 300px; - /*height: 150px;*/ - margin-top: -100px; - margin-left: -158px; - text-align: center; - display: block; + padding: 8px; + margin: 0px; + background-color: #000000; + color: #ffffff; + font-family: Verdana, arial, helvetica, sans-serif; + font-size: 14px; + position: absolute; + top: 50%; + left: 50%; + width: 300px; + /*height: 150px;*/ + margin-top: -100px; + margin-left: -158px; + text-align: center; + display: block; } -.snake-try-again-dialog, .snake-win-dialog { - padding: 8px; - margin: 0px; - background-color: #000000; - color: #ffffff; - font-family: Verdana, arial, helvetica, sans-serif; - font-size: 14px; - position: absolute; - top: 50%; - left: 50%; - width: 300px; - height: 100px; - margin-top: -75px; - margin-left: -158px; - text-align: center; - display: none; +.snake-try-again-dialog, +.snake-win-dialog { + padding: 8px; + margin: 0px; + background-color: #000000; + color: #ffffff; + font-family: Verdana, arial, helvetica, sans-serif; + font-size: 14px; + position: absolute; + top: 50%; + left: 50%; + width: 300px; + height: 100px; + margin-top: -75px; + margin-left: -158px; + text-align: center; + display: none; } diff --git a/src/css/dark-snake.css b/src/css/dark-snake.css index 8603a1cb..16388e41 100644 --- a/src/css/dark-snake.css +++ b/src/css/dark-snake.css @@ -5,29 +5,33 @@ http://patorjk.com/games/snake */ body { - margin:0px; - padding:0px; - background-color:#3E2E44; + margin: 0px; + padding: 0px; + background-color: #3e2e44; } .snake-toolbar { - color: #938996; + color: #938996; } #game-area { - margin:10px; - padding:0px; + margin: 10px; + padding: 0px; } -#game-area:focus { outline: none; } +#game-area:focus { + outline: none; +} #mode-wrapper { - font-family: Verdana, arial, helvetica, sans-serif; - font-size: 14px; - color: #938996; + font-family: Verdana, arial, helvetica, sans-serif; + font-size: 14px; + color: #938996; } -a.snake-link, a.snake-link:link, a.snake-link:visited { +a.snake-link, +a.snake-link:link, +a.snake-link:visited { color: #938996; } @@ -36,106 +40,107 @@ a.snake-link:hover { } .snake-pause-screen { - font-family: Verdana, arial, helvetica, sans-serif; - font-size: 14px; - position:absolute; - width:300px; - height:80px; - text-align:center; - top:50%; - left:50%; - margin-top:-40px; - margin-left:-150px; - display:none; - background-color:#3E2E44; - color: #938996; + font-family: Verdana, arial, helvetica, sans-serif; + font-size: 14px; + position: absolute; + width: 300px; + height: 80px; + text-align: center; + top: 50%; + left: 50%; + margin-top: -40px; + margin-left: -150px; + display: none; + background-color: #3e2e44; + color: #938996; } .snake-panel-component { - position: absolute; - font-family: Verdana, arial, helvetica, sans-serif; - font-size: 14px; - color: #938996; - text-align: center; - background-color: #3E2E44; - padding: 8px; - margin: 0px; + position: absolute; + font-family: Verdana, arial, helvetica, sans-serif; + font-size: 14px; + color: #938996; + text-align: center; + background-color: #3e2e44; + padding: 8px; + margin: 0px; } .snake-snakebody-block { - margin: 0px; - padding: 0px; - background-color: #3E2E44; - position: absolute; - border: 0px solid black; - background-repeat: no-repeat; + margin: 0px; + padding: 0px; + background-color: #3e2e44; + position: absolute; + border: 0px solid black; + background-repeat: no-repeat; } .snake-snakebody-alive { - background-image: url('src/css/images/dark-snakeblock.png'); + background-image: url("src/css/images/dark-snakeblock.png"); } .snake-snakebody-dead { - background-image: url('src/css/images/dead-dark-snakeblock.png'); + background-image: url("src/css/images/dead-dark-snakeblock.png"); } .snake-food-block { - margin: 0px; - padding: 0px; - background-color: black; - border: 2px solid #3E2E44; - position: absolute; + margin: 0px; + padding: 0px; + background-color: black; + border: 2px solid #3e2e44; + position: absolute; } .snake-playing-field { - margin: 0px; - padding: 0px; - position: absolute; - background-color: #312E44; - border: 3px solid black; + margin: 0px; + padding: 0px; + position: absolute; + background-color: #312e44; + border: 3px solid black; } .snake-game-container { - margin: 0px; - padding: 0px; - border-width: 0px; - border-style: none; - zoom: 1; - background-color: #3E2E44; - position: relative; + margin: 0px; + padding: 0px; + border-width: 0px; + border-style: none; + zoom: 1; + background-color: #3e2e44; + position: relative; } .snake-welcome-dialog { - padding: 8px; - margin: 0px; - background-color: black; - color: #938996; - font-family: Verdana, arial, helvetica, sans-serif; - font-size: 14px; - position: absolute; - top: 50%; - left: 50%; - width: 300px; - /*height: 150px;*/ - margin-top: -100px; - margin-left: -158px; - text-align: center; - display: block; -} - -.snake-try-again-dialog, .snake-win-dialog { - padding: 8px; - margin: 0px; - background-color: black; - color: #938996; - font-family: Verdana, arial, helvetica, sans-serif; - font-size: 14px; - position: absolute; - top: 50%; - left: 50%; - width: 300px; - height: 100px; - margin-top: -75px; - margin-left: -158px; - text-align: center; - display: none; + padding: 8px; + margin: 0px; + background-color: black; + color: #938996; + font-family: Verdana, arial, helvetica, sans-serif; + font-size: 14px; + position: absolute; + top: 50%; + left: 50%; + width: 300px; + /*height: 150px;*/ + margin-top: -100px; + margin-left: -158px; + text-align: center; + display: block; +} + +.snake-try-again-dialog, +.snake-win-dialog { + padding: 8px; + margin: 0px; + background-color: black; + color: #938996; + font-family: Verdana, arial, helvetica, sans-serif; + font-size: 14px; + position: absolute; + top: 50%; + left: 50%; + width: 300px; + height: 100px; + margin-top: -75px; + margin-left: -158px; + text-align: center; + display: none; } diff --git a/src/css/green-snake.css b/src/css/green-snake.css index 64cf1564..9cd114c5 100644 --- a/src/css/green-snake.css +++ b/src/css/green-snake.css @@ -4,140 +4,144 @@ By Patrick Gillespie http://patorjk.com/games/snake */ body { - margin:0px; - padding:0px; - background-color: darkgreen; + margin: 0px; + padding: 0px; + background-color: darkgreen; } .snake-toolbar { - background-color: rgba(255,255,255,0.4); - border-radius: 10px; + background-color: rgba(255, 255, 255, 0.4); + border-radius: 10px; } #game-area { - margin:10px; - padding:0px; - background-color: lightgreen; + margin: 10px; + padding: 0px; + background-color: lightgreen; } #mode-wrapper { - color: #ffffff; - font-family: Verdana, arial, helvetica, sans-serif; - font-size: 14px; - + color: #ffffff; + font-family: Verdana, arial, helvetica, sans-serif; + font-size: 14px; } -#game-area:focus { outline: none; } +#game-area:focus { + outline: none; +} -a.snake-link, a.snake-link:link, a.snake-link:visited { +a.snake-link, +a.snake-link:link, +a.snake-link:visited { color: black; } a.snake-link:hover { - color: #FfFf54; + color: #ffff54; } .snake-pause-screen { - font-family: Verdana, arial, helvetica, sans-serif; - font-size: 14px; - position:absolute; - width:300px; - height:80px; - text-align:center; - top:50%; - left:50%; - margin-top:-40px; - margin-left:-150px; - display:none; - background-color:black; - color:white; + font-family: Verdana, arial, helvetica, sans-serif; + font-size: 14px; + position: absolute; + width: 300px; + height: 80px; + text-align: center; + top: 50%; + left: 50%; + margin-top: -40px; + margin-left: -150px; + display: none; + background-color: black; + color: white; } .snake-panel-component { - position: absolute; - font-family: Verdana, arial, helvetica, sans-serif; - font-size: 14px; - color: black; - text-align: center; - background-color: white; - padding: 8px; - margin: 0px; + position: absolute; + font-family: Verdana, arial, helvetica, sans-serif; + font-size: 14px; + color: black; + text-align: center; + background-color: white; + padding: 8px; + margin: 0px; } .snake-snakebody-block { - margin: 0px; - padding: 0px; - background-color: #FF0000; - position: absolute; - border: 0px solid #000080; - background-repeat: no-repeat; + margin: 0px; + padding: 0px; + background-color: #ff0000; + position: absolute; + border: 0px solid #000080; + background-repeat: no-repeat; } .snake-snakebody-alive { - background-image: url('src/css/images/snakeblock.png'); + background-image: url("src/css/images/snakeblock.png"); } .snake-snakebody-dead { - background-image: url('src/css/images/deadblock.png'); + background-image: url("src/css/images/deadblock.png"); } .snake-food-block { - margin: 0px; - padding: 0px; - background-color: black; - border: 0px solid #000080; - position: absolute; + margin: 0px; + padding: 0px; + background-color: black; + border: 0px solid #000080; + position: absolute; } .snake-playing-field { - margin: 0px; - padding: 0px; - position: absolute; - background-color: white; - border: 0px solid #0000A8; + margin: 0px; + padding: 0px; + position: absolute; + background-color: white; + border: 0px solid #0000a8; } .snake-game-container { - margin: 0px; - padding: 0px; - border-width: 0px; - border-style: none; - zoom: 1; - background-color: #FC5454; - position: relative; + margin: 0px; + padding: 0px; + border-width: 0px; + border-style: none; + zoom: 1; + background-color: #fc5454; + position: relative; } .snake-welcome-dialog { - padding: 8px; - margin: 0px; - background-color: #000000; - color: #ffffff; - font-family: Verdana, arial, helvetica, sans-serif; - font-size: 14px; - position: absolute; - top: 50%; - left: 50%; - width: 300px; - /*height: 150px;*/ - margin-top: -100px; - margin-left: -158px; - text-align: center; - display: block; -} - -.snake-try-again-dialog, .snake-win-dialog { - padding: 8px; - margin: 0px; - background-color: #000000; - color: #ffffff; - font-family: Verdana, arial, helvetica, sans-serif; - font-size: 14px; - position: absolute; - top: 50%; - left: 50%; - width: 300px; - height: 100px; - margin-top: -75px; - margin-left: -158px; - text-align: center; - display: none; + padding: 8px; + margin: 0px; + background-color: #000000; + color: #ffffff; + font-family: Verdana, arial, helvetica, sans-serif; + font-size: 14px; + position: absolute; + top: 50%; + left: 50%; + width: 300px; + /*height: 150px;*/ + margin-top: -100px; + margin-left: -158px; + text-align: center; + display: block; +} + +.snake-try-again-dialog, +.snake-win-dialog { + padding: 8px; + margin: 0px; + background-color: #000000; + color: #ffffff; + font-family: Verdana, arial, helvetica, sans-serif; + font-size: 14px; + position: absolute; + top: 50%; + left: 50%; + width: 300px; + height: 100px; + margin-top: -75px; + margin-left: -158px; + text-align: center; + display: none; } diff --git a/src/css/head-snake.css b/src/css/head-snake.css index e077a44a..0e7daf95 100644 --- a/src/css/head-snake.css +++ b/src/css/head-snake.css @@ -1,142 +1,148 @@ body { - margin:0px; - padding:0px; - background-color: rgb(0, 0, 0); + margin: 0px; + padding: 0px; + background-color: rgb(0, 0, 0); } #game-area { - margin:10px; - padding:0px; + margin: 10px; + padding: 0px; } #mode-wrapper { - color: #ffffff; - font-family: Verdana, arial, helvetica, sans-serif; - font-size: 14px; - + color: #ffffff; + font-family: Verdana, arial, helvetica, sans-serif; + font-size: 14px; } -#game-area:focus { outline: none; } +#game-area:focus { + outline: none; +} -a.snake-link, a.snake-link:link, a.snake-link:visited { - color: #FCFC54; +a.snake-link, +a.snake-link:link, +a.snake-link:visited { + color: #fcfc54; } a.snake-link:hover { - color: #FfFf54; + color: #ffff54; } .snake-pause-screen { - font-family: Verdana, arial, helvetica, sans-serif; - font-size: 14px; - position:absolute; - width:300px; - height:80px; - text-align:center; - top:50%; - left:50%; - margin-top:-40px; - margin-left:-150px; - display:none; - background-color:black; - color:white; + font-family: Verdana, arial, helvetica, sans-serif; + font-size: 14px; + position: absolute; + width: 300px; + height: 80px; + text-align: center; + top: 50%; + left: 50%; + margin-top: -40px; + margin-left: -150px; + display: none; + background-color: black; + color: white; } .snake-panel-component { - position: absolute; - font-family: Verdana, arial, helvetica, sans-serif; - font-size: 14px; - color: #ffffff; - text-align: center; - padding: 8px; - margin: 0px; + position: absolute; + font-family: Verdana, arial, helvetica, sans-serif; + font-size: 14px; + color: #ffffff; + text-align: center; + padding: 8px; + margin: 0px; } #snake-snakehead-alive { - background-image: url('src/css/images/green-head-snakeblock.png'); - margin: 0px; - padding: 0px; - background-color: rgb(10, 173, 10); - position: absolute; - border: 0px solid #000080; - background-repeat: no-repeat; - border-radius: 4px; + background-image: url("src/css/images/green-head-snakeblock.png"); + margin: 0px; + padding: 0px; + background-color: rgb(10, 173, 10); + position: absolute; + border: 0px solid #000080; + background-repeat: no-repeat; + border-radius: 4px; } .snake-snakebody-block { - margin: 0px; - padding: 0px; - background-color: #FF0000; - position: absolute; - border: 0px solid #000080; - background-repeat: no-repeat; + margin: 0px; + padding: 0px; + background-color: #ff0000; + position: absolute; + border: 0px solid #000080; + background-repeat: no-repeat; } .snake-snakebody-alive { - background-image: url('src/css/images/green-body-snakeblock.png'), url('src/css/images/green-body-snakeblock.png'); + background-image: url("src/css/images/green-body-snakeblock.png"), + url("src/css/images/green-body-snakeblock.png"); } .snake-snakebody-dead { - background-image: url('src/css/images/deadblock.png'), url('src/css/images/deadblock.png'); + background-image: url("src/css/images/deadblock.png"), + url("src/css/images/deadblock.png"); } .snake-food-block { - margin: 0px; - padding: 0px; - background-color: rgb(182, 11, 11); - border: 0px solid #000080; - position: absolute; - border-radius: 6px; + margin: 0px; + padding: 0px; + background-color: rgb(182, 11, 11); + border: 0px solid #000080; + position: absolute; + border-radius: 6px; } .snake-playing-field { - margin: 0px; - padding: 0px; - position: absolute; - background-color: rgb(245, 245, 220); - border: 0px solid #0000A8; + margin: 0px; + padding: 0px; + position: absolute; + background-color: rgb(245, 245, 220); + border: 0px solid #0000a8; } .snake-game-container { - margin: 0px; - padding: 0px; - border-width: 0px; - border-style: none; - zoom: 1; - position: relative; + margin: 0px; + padding: 0px; + border-width: 0px; + border-style: none; + zoom: 1; + position: relative; } .snake-welcome-dialog { - padding: 8px; - margin: 0px; - background-color: #000000; - color: #ffffff; - font-family: Verdana, arial, helvetica, sans-serif; - font-size: 14px; - position: absolute; - top: 50%; - left: 50%; - width: 300px; - /*height: 150px;*/ - margin-top: -100px; - margin-left: -158px; - text-align: center; - display: block; -} - -.snake-try-again-dialog, .snake-win-dialog { - padding: 8px; - margin: 0px; - background-color: #000000; - color: #ffffff; - font-family: Verdana, arial, helvetica, sans-serif; - font-size: 14px; - position: absolute; - top: 50%; - left: 50%; - width: 300px; - height: 100px; - margin-top: -75px; - margin-left: -158px; - text-align: center; - display: none; + padding: 8px; + margin: 0px; + background-color: #000000; + color: #ffffff; + font-family: Verdana, arial, helvetica, sans-serif; + font-size: 14px; + position: absolute; + top: 50%; + left: 50%; + width: 300px; + /*height: 150px;*/ + margin-top: -100px; + margin-left: -158px; + text-align: center; + display: block; +} + +.snake-try-again-dialog, +.snake-win-dialog { + padding: 8px; + margin: 0px; + background-color: #000000; + color: #ffffff; + font-family: Verdana, arial, helvetica, sans-serif; + font-size: 14px; + position: absolute; + top: 50%; + left: 50%; + width: 300px; + height: 100px; + margin-top: -75px; + margin-left: -158px; + text-align: center; + display: none; } diff --git a/src/css/light-snake.css b/src/css/light-snake.css index 3829ee4e..db0be890 100644 --- a/src/css/light-snake.css +++ b/src/css/light-snake.css @@ -5,120 +5,123 @@ http://patorjk.com/games/snake */ body { - margin: 0px; - padding: 0px; - background-color: #f73378; + margin: 0px; + padding: 0px; + background-color: #f73378; } #game-area { - margin: 10px; - padding: 0px; + margin: 10px; + padding: 0px; } #mode-wrapper { - color: #ffffff; - font-family: Verdana, arial, helvetica, sans-serif; - font-size: 14px; + color: #ffffff; + font-family: Verdana, arial, helvetica, sans-serif; + font-size: 14px; } #game-area:focus { - outline: none; + outline: none; } -a.snake-link, a.snake-link:link, a.snake-link:visited { - color: #FCFC54; +a.snake-link, +a.snake-link:link, +a.snake-link:visited { + color: #fcfc54; } a.snake-link:hover { - color: #FfFf54; + color: #ffff54; } .snake-pause-screen { - font-family: Verdana, arial, helvetica, sans-serif; - font-size: 14px; - position: absolute; - width: 300px; - height: 80px; - text-align: center; - top: 50%; - left: 50%; - margin-top: -40px; - margin-left: -150px; - display: none; - background-color: black; - color: white; + font-family: Verdana, arial, helvetica, sans-serif; + font-size: 14px; + position: absolute; + width: 300px; + height: 80px; + text-align: center; + top: 50%; + left: 50%; + margin-top: -40px; + margin-left: -150px; + display: none; + background-color: black; + color: white; } .snake-panel-component { - position: absolute; - font-family: Verdana, arial, helvetica, sans-serif; - font-size: 14px; - color: #ffffff; - text-align: center; - padding: 8px; - margin: 0px; + position: absolute; + font-family: Verdana, arial, helvetica, sans-serif; + font-size: 14px; + color: #ffffff; + text-align: center; + padding: 8px; + margin: 0px; } .snake-snakebody-block { - margin: 0px; - padding: 0px; - background-color: #FF0000; - position: absolute; - border: 0px solid #000080; - background-repeat: no-repeat; + margin: 0px; + padding: 0px; + background-color: #ff0000; + position: absolute; + border: 0px solid #000080; + background-repeat: no-repeat; } .snake-snakebody-alive { - background-image: url('src/css/images/snakeblock.png'); + background-image: url("src/css/images/snakeblock.png"); } .snake-snakebody-dead { - background-image: url('src/css/images/deadblock.png'); + background-image: url("src/css/images/deadblock.png"); } .snake-food-block { - margin: 0px; - padding: 0px; - background-color: #6cfd6a; - border: 0px solid #000080; - position: absolute; + margin: 0px; + padding: 0px; + background-color: #6cfd6a; + border: 0px solid #000080; + position: absolute; } .snake-playing-field { - margin: 0px; - padding: 0px; - position: absolute; - background-color: #ab003c; - border: 0px solid #ab003c; + margin: 0px; + padding: 0px; + position: absolute; + background-color: #ab003c; + border: 0px solid #ab003c; } .snake-game-container { - margin: 0px; - padding: 0px; - border-width: 0px; - border-style: none; - zoom: 1; - position: relative; + margin: 0px; + padding: 0px; + border-width: 0px; + border-style: none; + zoom: 1; + position: relative; } .snake-welcome-dialog { - padding: 8px; - margin: 0px; - background-color: #000000; - color: #ffffff; - font-family: Verdana, arial, helvetica, sans-serif; - font-size: 14px; - position: absolute; - top: 50%; - left: 50%; - width: 300px; - /*height: 150px;*/ - margin-top: -100px; - margin-left: -158px; - text-align: center; - display: block; -} -.snake-try-again-dialog, .snake-win-dialog { - padding: 8px; - margin: 0px; - background-color: #000000; - color: #ffffff; - font-family: Verdana, arial, helvetica, sans-serif; - font-size: 14px; - position: absolute; - top: 50%; - left: 50%; - width: 300px; - height: 100px; - margin-top: -75px; - margin-left: -158px; - text-align: center; - display: none; + padding: 8px; + margin: 0px; + background-color: #000000; + color: #ffffff; + font-family: Verdana, arial, helvetica, sans-serif; + font-size: 14px; + position: absolute; + top: 50%; + left: 50%; + width: 300px; + /*height: 150px;*/ + margin-top: -100px; + margin-left: -158px; + text-align: center; + display: block; +} +.snake-try-again-dialog, +.snake-win-dialog { + padding: 8px; + margin: 0px; + background-color: #000000; + color: #ffffff; + font-family: Verdana, arial, helvetica, sans-serif; + font-size: 14px; + position: absolute; + top: 50%; + left: 50%; + width: 300px; + height: 100px; + margin-top: -75px; + margin-left: -158px; + text-align: center; + display: none; } diff --git a/src/css/main-snake.css b/src/css/main-snake.css index 5623c07e..7938bf34 100755 --- a/src/css/main-snake.css +++ b/src/css/main-snake.css @@ -4,132 +4,137 @@ By Patrick Gillespie http://patorjk.com/games/snake */ body { - margin:0px; - padding:0px; - background-color: #FC5454; + margin: 0px; + padding: 0px; + background-color: #fc5454; } #game-area { - margin:10px; - padding:0px; + margin: 10px; + padding: 0px; } #mode-wrapper { - color: #ffffff; - font-family: Verdana, arial, helvetica, sans-serif; - font-size: 14px; - + color: #ffffff; + font-family: Verdana, arial, helvetica, sans-serif; + font-size: 14px; } -#game-area:focus { outline: none; } +#game-area:focus { + outline: none; +} -a.snake-link, a.snake-link:link, a.snake-link:visited { - color: #FCFC54; +a.snake-link, +a.snake-link:link, +a.snake-link:visited { + color: #fcfc54; } a.snake-link:hover { - color: #FfFf54; + color: #ffff54; } .snake-pause-screen { - font-family: Verdana, arial, helvetica, sans-serif; - font-size: 14px; - position:absolute; - width:300px; - height:80px; - text-align:center; - top:50%; - left:50%; - margin-top:-40px; - margin-left:-150px; - display:none; - background-color:black; - color:white; + font-family: Verdana, arial, helvetica, sans-serif; + font-size: 14px; + position: absolute; + width: 300px; + height: 80px; + text-align: center; + top: 50%; + left: 50%; + margin-top: -40px; + margin-left: -150px; + display: none; + background-color: black; + color: white; } .snake-panel-component { - position: absolute; - font-family: Verdana, arial, helvetica, sans-serif; - font-size: 14px; - color: #ffffff; - text-align: center; - padding: 8px; - margin: 0px; + position: absolute; + font-family: Verdana, arial, helvetica, sans-serif; + font-size: 14px; + color: #ffffff; + text-align: center; + padding: 8px; + margin: 0px; } .snake-snakebody-block { - margin: 0px; - padding: 0px; - background-color: #FF0000; - position: absolute; - border: 0px solid #000080; - background-repeat: no-repeat; + margin: 0px; + padding: 0px; + background-color: #ff0000; + position: absolute; + border: 0px solid #000080; + background-repeat: no-repeat; } .snake-snakebody-alive { - background-image: url('./images/snakeblock.png'), url('./images/snakeblock.png'); + background-image: url("./images/snakeblock.png"), + url("./images/snakeblock.png"); } .snake-snakebody-dead { - background-image: url('./images/deadblock.png'), url('./images/deadblock.png'); + background-image: url("./images/deadblock.png"), url("./images/deadblock.png"); } .snake-food-block { - margin: 0px; - padding: 0px; - background-color: #FF0000; - border: 0px solid #000080; - position: absolute; + margin: 0px; + padding: 0px; + background-color: #ff0000; + border: 0px solid #000080; + position: absolute; } .snake-playing-field { - margin: 0px; - padding: 0px; - position: absolute; - background-color: #0000A8; - border: 0px solid #0000A8; + margin: 0px; + padding: 0px; + position: absolute; + background-color: #0000a8; + border: 0px solid #0000a8; } .snake-game-container { - margin: 0px; - padding: 0px; - border-width: 0px; - border-style: none; - zoom: 1; - position: relative; + margin: 0px; + padding: 0px; + border-width: 0px; + border-style: none; + zoom: 1; + position: relative; } .snake-welcome-dialog { - padding: 8px; - margin: 0px; - background-color: #000000; - color: #ffffff; - font-family: Verdana, arial, helvetica, sans-serif; - font-size: 14px; - position: absolute; - top: 50%; - left: 50%; - width: 300px; - /*height: 150px;*/ - margin-top: -100px; - margin-left: -158px; - text-align: center; - display: block; + padding: 8px; + margin: 0px; + background-color: #000000; + color: #ffffff; + font-family: Verdana, arial, helvetica, sans-serif; + font-size: 14px; + position: absolute; + top: 50%; + left: 50%; + width: 300px; + /*height: 150px;*/ + margin-top: -100px; + margin-left: -158px; + text-align: center; + display: block; } -.snake-try-again-dialog, .snake-win-dialog { - padding: 8px; - margin: 0px; - background-color: #000000; - color: #ffffff; - font-family: Verdana, arial, helvetica, sans-serif; - font-size: 14px; - position: absolute; - top: 50%; - left: 50%; - width: 300px; - height: 100px; - margin-top: -75px; - margin-left: -158px; - text-align: center; - display: none; +.snake-try-again-dialog, +.snake-win-dialog { + padding: 8px; + margin: 0px; + background-color: #000000; + color: #ffffff; + font-family: Verdana, arial, helvetica, sans-serif; + font-size: 14px; + position: absolute; + top: 50%; + left: 50%; + width: 300px; + height: 100px; + margin-top: -75px; + margin-left: -158px; + text-align: center; + display: none; } diff --git a/src/css/neon-snake.css b/src/css/neon-snake.css index 31b3291f..49591510 100644 --- a/src/css/neon-snake.css +++ b/src/css/neon-snake.css @@ -1,139 +1,145 @@ -/* -JavaScript Snake -By Patrick Gillespie -http://patorjk.com/games/snake -*/ -body { - margin:0px; - padding:0px; - background-color: #000000; -} - -.snake-toolbar { - color: #ffffff; -} - -#game-area { - margin:10px; - padding:0px; -} - -#mode-wrapper { - color: #ffffff; - font-family: Verdana, arial, helvetica, sans-serif; - font-size: 14px; - -} - -#game-area:focus { outline: none; } - -a.snake-link, a.snake-link:link, a.snake-link:visited { - color: #00FFE0; -} - -a.snake-link:hover { - color: #0FFF00; -} - -.snake-pause-screen { - font-family: Verdana, arial, helvetica, sans-serif; - font-size: 14px; - position:absolute; - width:300px; - height:80px; - text-align:center; - top:50%; - left:50%; - margin-top:-40px; - margin-left:-150px; - display:none; - background-color:#0FFF00; - color:#000000; -} - -.snake-panel-component { - position: absolute; - font-family: Verdana, arial, helvetica, sans-serif; - font-size: 14px; - color: #ffffff; - text-align: center; - padding: 8px; - margin: 0px; -} - -.snake-snakebody-block { - margin: 0px; - padding: 0px; - background-color: #FF0000; - position: absolute; - border: 0px solid #000080; - background-repeat: no-repeat; -} - -.snake-snakebody-alive { - background-image: url('src/css/images/neon-body-snakeblock.png'), url('src/cssss/images/neon-body-snakeblock.png'); -} -.snake-snakebody-dead { - background-image: url('src/css/images/neon-dead-snakeblock.png'), url('src/cssss/images/neon-dead-snakeblock.png'); -} - -.snake-food-block { - margin: 0px; - padding: 0px; - background-color: #FF0000; - border: 0px solid #000080; - position: absolute; -} - -.snake-playing-field { - margin: 0px; - padding: 0px; - position: absolute; - background-color: #00FFD4; - border: 0px solid #0000A8; -} - -.snake-game-container { - margin: 0px; - padding: 0px; - border-width: 0px; - border-style: none; - zoom: 1; - position: relative; -} - -.snake-welcome-dialog { - padding: 8px; - margin: 0px; - background-color: #0FFF00; - color: #000000; - font-family: Verdana, arial, helvetica, sans-serif; - font-size: 14px; - position: absolute; - top: 50%; - left: 50%; - width: 300px; - /*height: 150px;*/ - margin-top: -100px; - margin-left: -158px; - text-align: center; - display: block; -} - -.snake-try-again-dialog, .snake-win-dialog { - padding: 8px; - margin: 0px; - background-color: #0FFF00; - color: #000000; - font-family: Verdana, arial, helvetica, sans-serif; - font-size: 14px; - position: absolute; - top: 50%; - left: 50%; - width: 300px; - height: 100px; - margin-top: -75px; - margin-left: -158px; - text-align: center; - display: none; -} +/* +JavaScript Snake +By Patrick Gillespie +http://patorjk.com/games/snake +*/ +body { + margin: 0px; + padding: 0px; + background-color: #000000; +} + +.snake-toolbar { + color: #ffffff; +} + +#game-area { + margin: 10px; + padding: 0px; +} + +#mode-wrapper { + color: #ffffff; + font-family: Verdana, arial, helvetica, sans-serif; + font-size: 14px; +} + +#game-area:focus { + outline: none; +} + +a.snake-link, +a.snake-link:link, +a.snake-link:visited { + color: #00ffe0; +} + +a.snake-link:hover { + color: #0fff00; +} + +.snake-pause-screen { + font-family: Verdana, arial, helvetica, sans-serif; + font-size: 14px; + position: absolute; + width: 300px; + height: 80px; + text-align: center; + top: 50%; + left: 50%; + margin-top: -40px; + margin-left: -150px; + display: none; + background-color: #0fff00; + color: #000000; +} + +.snake-panel-component { + position: absolute; + font-family: Verdana, arial, helvetica, sans-serif; + font-size: 14px; + color: #ffffff; + text-align: center; + padding: 8px; + margin: 0px; +} + +.snake-snakebody-block { + margin: 0px; + padding: 0px; + background-color: #ff0000; + position: absolute; + border: 0px solid #000080; + background-repeat: no-repeat; +} + +.snake-snakebody-alive { + background-image: url("src/css/images/neon-body-snakeblock.png"), + url("src/cssss/images/neon-body-snakeblock.png"); +} +.snake-snakebody-dead { + background-image: url("src/css/images/neon-dead-snakeblock.png"), + url("src/cssss/images/neon-dead-snakeblock.png"); +} + +.snake-food-block { + margin: 0px; + padding: 0px; + background-color: #ff0000; + border: 0px solid #000080; + position: absolute; +} + +.snake-playing-field { + margin: 0px; + padding: 0px; + position: absolute; + background-color: #00ffd4; + border: 0px solid #0000a8; +} + +.snake-game-container { + margin: 0px; + padding: 0px; + border-width: 0px; + border-style: none; + zoom: 1; + position: relative; +} + +.snake-welcome-dialog { + padding: 8px; + margin: 0px; + background-color: #0fff00; + color: #000000; + font-family: Verdana, arial, helvetica, sans-serif; + font-size: 14px; + position: absolute; + top: 50%; + left: 50%; + width: 300px; + /*height: 150px;*/ + margin-top: -100px; + margin-left: -158px; + text-align: center; + display: block; +} + +.snake-try-again-dialog, +.snake-win-dialog { + padding: 8px; + margin: 0px; + background-color: #0fff00; + color: #000000; + font-family: Verdana, arial, helvetica, sans-serif; + font-size: 14px; + position: absolute; + top: 50%; + left: 50%; + width: 300px; + height: 100px; + margin-top: -75px; + margin-left: -158px; + text-align: center; + display: none; +} diff --git a/src/css/teal-snake.css b/src/css/teal-snake.css index 8fbe6ffa..ac06471a 100644 --- a/src/css/teal-snake.css +++ b/src/css/teal-snake.css @@ -3,34 +3,37 @@ JavaScript Snake By Patrick Gillespie http://patorjk.com/games/snake */ -@import url('https://fonts.googleapis.com/css2?family=Electrolize&display=swap'); - +@import url("https://fonts.googleapis.com/css2?family=Electrolize&display=swap"); body { - margin:0px; - padding:0px; - background-color:teal; + margin: 0px; + padding: 0px; + background-color: teal; } .snake-toolbar { - font-family: Electrolize; - color: white; + font-family: Electrolize; + color: white; } #game-area { - margin:10px; - padding:0px; + margin: 10px; + padding: 0px; } -#game-area:focus { outline: none; } +#game-area:focus { + outline: none; +} #mode-wrapper { - font-family: Electrolize; - font-size: 14px; - color: whitesmoke; + font-family: Electrolize; + font-size: 14px; + color: whitesmoke; } -a.snake-link, a.snake-link:link, a.snake-link:visited { +a.snake-link, +a.snake-link:link, +a.snake-link:visited { color: white; } @@ -39,106 +42,107 @@ a.snake-link:hover { } .snake-pause-screen { - font-family: Electrolize; - font-size: 16px; - position:absolute; - width:300px; - height:80px; - text-align:center; - top:50%; - left:50%; - margin-top:-40px; - margin-left:-150px; - display:none; - background-color:#3E2E44; - color: whitesmoke; + font-family: Electrolize; + font-size: 16px; + position: absolute; + width: 300px; + height: 80px; + text-align: center; + top: 50%; + left: 50%; + margin-top: -40px; + margin-left: -150px; + display: none; + background-color: #3e2e44; + color: whitesmoke; } .snake-panel-component { - position: absolute; - font-family: Electrolize; - font-size: 16px; - color: #938996; - text-align: center; - background-color: #3E2E44; - padding: 8px; - margin: 0px; + position: absolute; + font-family: Electrolize; + font-size: 16px; + color: #938996; + text-align: center; + background-color: #3e2e44; + padding: 8px; + margin: 0px; } .snake-snakebody-block { - margin: 0px; - padding: 0px; - background-color: orange; - position: absolute; - border: 0px solid black; - background-repeat: no-repeat; + margin: 0px; + padding: 0px; + background-color: orange; + position: absolute; + border: 0px solid black; + background-repeat: no-repeat; } .snake-snakebody-alive { - background-image: url('src/css/images/snakeblock.png'); + background-image: url("src/css/images/snakeblock.png"); } .snake-snakebody-dead { - background-image: url('src/css/images/dead-dark-snakeblock.png'); + background-image: url("src/css/images/dead-dark-snakeblock.png"); } .snake-food-block { - margin: 0px; - padding: 0px; - background-color: red; - border: 2px solid black; - position: absolute; + margin: 0px; + padding: 0px; + background-color: red; + border: 2px solid black; + position: absolute; } .snake-playing-field { - margin: 0px; - padding: 0px; - position: absolute; - background-color: rgb(0, 180, 180); - border: 3px solid black; + margin: 0px; + padding: 0px; + position: absolute; + background-color: rgb(0, 180, 180); + border: 3px solid black; } .snake-game-container { - margin: 0px; - padding: 0px; - border-width: 0px; - border-style: none; - zoom: 1; - background-color: #3E2E44; - position: relative; + margin: 0px; + padding: 0px; + border-width: 0px; + border-style: none; + zoom: 1; + background-color: #3e2e44; + position: relative; } .snake-welcome-dialog { - padding: 8px; - margin: 0px; - background-color: black; - color: whitesmoke; - font-family: Electrolize; - font-size: 14px; - position: absolute; - top: 50%; - left: 50%; - width: 300px; - /*height: 150px;*/ - margin-top: -100px; - margin-left: -158px; - text-align: center; - display: block; -} - -.snake-try-again-dialog, .snake-win-dialog { - padding: 8px; - margin: 0px; - background-color: black; - color: whitesmoke; - font-family: Electrolize; - font-size: 16px; - position: absolute; - top: 50%; - left: 50%; - width: 300px; - height: 100px; - margin-top: -75px; - margin-left: -158px; - text-align: center; - display: none; + padding: 8px; + margin: 0px; + background-color: black; + color: whitesmoke; + font-family: Electrolize; + font-size: 14px; + position: absolute; + top: 50%; + left: 50%; + width: 300px; + /*height: 150px;*/ + margin-top: -100px; + margin-left: -158px; + text-align: center; + display: block; +} + +.snake-try-again-dialog, +.snake-win-dialog { + padding: 8px; + margin: 0px; + background-color: black; + color: whitesmoke; + font-family: Electrolize; + font-size: 16px; + position: absolute; + top: 50%; + left: 50%; + width: 300px; + height: 100px; + margin-top: -75px; + margin-left: -158px; + text-align: center; + display: none; } diff --git a/src/index.html b/src/index.html index 360fe818..d29237b0 100755 --- a/src/index.html +++ b/src/index.html @@ -1,154 +1,147 @@ - + - - - + --> + JavaScript Snake - + - + +
-
+
Theme:
-
+
Mode:
-
+ +
- -
-
+
-
-
+
- + + diff --git a/src/js/ai-init.js b/src/js/ai-init.js new file mode 100644 index 00000000..daddd8b8 --- /dev/null +++ b/src/js/ai-init.js @@ -0,0 +1,21 @@ +const mySnakeBoard = new SNAKE.Board({ + boardContainer: "game-area", + fullScreen: true, + premoveOnPause: false, + onLengthUpdate: (length) => { + console.log(`Length: ${length}`); + }, + onPauseToggle: (isPaused) => { + console.log(`Is paused: ${isPaused}`); + }, + onInit: (params) => { + console.log("init!"); + console.log(params); + }, + onWin: () => { + console.log("wn!"); + }, + onDeath: () => { + console.log("dead!"); + }, +}); diff --git a/src/js/init.js b/src/js/init.js index 045d093f..daddd8b8 100644 --- a/src/js/init.js +++ b/src/js/init.js @@ -1,5 +1,21 @@ const mySnakeBoard = new SNAKE.Board({ boardContainer: "game-area", fullScreen: true, - premoveOnPause: false -}); \ No newline at end of file + premoveOnPause: false, + onLengthUpdate: (length) => { + console.log(`Length: ${length}`); + }, + onPauseToggle: (isPaused) => { + console.log(`Is paused: ${isPaused}`); + }, + onInit: (params) => { + console.log("init!"); + console.log(params); + }, + onWin: () => { + console.log("wn!"); + }, + onDeath: () => { + console.log("dead!"); + }, +}); diff --git a/src/js/snake.js b/src/js/snake.js index 103a5bdb..2bfe6a79 100644 --- a/src/js/snake.js +++ b/src/js/snake.js @@ -29,6 +29,14 @@ const MOVE_RIGHT = 1; const MIN_SNAKE_SPEED = 25; const RUSH_INCR = 5; +const DEFAULT_SNAKE_SPEED = 80; + +const BOARD_NOT_READY = 0; +const BOARD_READY = 1; +const BOARD_IN_PLAY = 2; + +const HIGH_SCORE_KEY = "jsSnakeHighScore"; + /** * @method addEventListener * @param {Object} obj The object to add an event listener to. @@ -75,426 +83,468 @@ SNAKE.removeEventListener = (function () { * @namespace SNAKE * @param {Object} config The configuration object for the class. Contains playingBoard (the SNAKE.Board that this snake resides in), startRow and startCol. */ -SNAKE.Snake = SNAKE.Snake || (function () { - - // ------------------------------------------------------------------------- - // Private static variables and methods - // ------------------------------------------------------------------------- - - const blockPool = []; - - const SnakeBlock = function () { - this.elm = null; - this.elmStyle = null; - this.row = -1; - this.col = -1; - this.next = null; - this.prev = null; - }; - - // this function is adapted from the example at http://greengeckodesign.com/blog/2007/07/get-highest-z-index-in-javascript.html - function getNextHighestZIndex(myObj) { - let highestIndex = 0, - currentIndex = 0, - ii; - for (ii in myObj) { - if (myObj[ii].elm.currentStyle) { - currentIndex = parseFloat(myObj[ii].elm.style["z-index"], 10); - } else if (window.getComputedStyle) { - currentIndex = parseFloat(document.defaultView.getComputedStyle(myObj[ii].elm, null).getPropertyValue("z-index"), 10); - } - if (!isNaN(currentIndex) && currentIndex > highestIndex) { - highestIndex = currentIndex; +SNAKE.Snake = + SNAKE.Snake || + (function () { + // ------------------------------------------------------------------------- + // Private static variables and methods + // ------------------------------------------------------------------------- + + const blockPool = []; + + const SnakeBlock = function () { + this.elm = null; + this.elmStyle = null; + this.row = -1; + this.col = -1; + this.next = null; + this.prev = null; + }; + + // this function is adapted from the example at http://greengeckodesign.com/blog/2007/07/get-highest-z-index-in-javascript.html + function getNextHighestZIndex(myObj) { + let highestIndex = 0, + currentIndex = 0, + ii; + for (ii in myObj) { + if (myObj[ii].elm.currentStyle) { + currentIndex = parseFloat(myObj[ii].elm.style["z-index"], 10); + } else if (window.getComputedStyle) { + currentIndex = parseFloat( + document.defaultView + .getComputedStyle(myObj[ii].elm, null) + .getPropertyValue("z-index"), + 10, + ); + } + if (!isNaN(currentIndex) && currentIndex > highestIndex) { + highestIndex = currentIndex; + } } + return highestIndex + 1; } - return (highestIndex + 1); - } - // ------------------------------------------------------------------------- - // Contructor + public and private definitions - // ------------------------------------------------------------------------- + // ------------------------------------------------------------------------- + // Contructor + public and private definitions + // ------------------------------------------------------------------------- - /* + /* config options: playingBoard - the SnakeBoard that this snake belongs too. startRow - The row the snake should start on. startCol - The column the snake should start on. + moveSnakeWithAI - function to move the snake with AI */ - return function (config) { + return function (config) { + if (!config || !config.playingBoard) { + return; + } + if (localStorage[HIGH_SCORE_KEY] === undefined) + localStorage.setItem(HIGH_SCORE_KEY, 0); + + // ----- private variables ----- + + const me = this; + const playingBoard = config.playingBoard; + const growthIncr = 5; + const columnShift = [0, 1, 0, -1]; + const rowShift = [-1, 0, 1, 0]; + + let lastMove = 1, + preMove = MOVE_NONE, + isFirstGameMove = true, + currentDirection = MOVE_NONE, // 0: up, 1: left, 2: down, 3: right + snakeSpeed = DEFAULT_SNAKE_SPEED, + isDead = false, + isPaused = false; + + const modeDropdown = document.getElementById("selectMode"); + if (modeDropdown) { + modeDropdown.addEventListener("change", function (evt) { + evt = evt || {}; + let val = evt.target + ? parseInt(evt.target.value) + : DEFAULT_SNAKE_SPEED; + + if (isNaN(val)) { + val = DEFAULT_SNAKE_SPEED; + } else if (val < MIN_SNAKE_SPEED) { + val = DEFAULT_SNAKE_SPEED; + } - if (!config || !config.playingBoard) { - return; - } - if (localStorage.jsSnakeHighScore === undefined) localStorage.setItem('jsSnakeHighScore', 0); - - // ----- private variables ----- - - const me = this; - const playingBoard = config.playingBoard; - const growthIncr = 5; - const columnShift = [0, 1, 0, -1]; - const rowShift = [-1, 0, 1, 0]; - - let lastMove = 1, - preMove = MOVE_NONE, - isFirstMove = true, - isFirstGameMove = true, - currentDirection = MOVE_NONE, // 0: up, 1: left, 2: down, 3: right - snakeSpeed = 80, - isDead = false, - isPaused = false; - - const modeDropdown = document.getElementById('selectMode'); - if (modeDropdown) { - modeDropdown.addEventListener('change', function (evt) { - evt = evt || {}; - let val = evt.target ? parseInt(evt.target.value) : 75; - - if (isNaN(val)) { - val = 75; - } else if (val < MIN_SNAKE_SPEED) { - val = 75 - } + snakeSpeed = val; - snakeSpeed = val; + setTimeout(function () { + document.getElementById("game-area").focus(); + }, 10); + }); + } - setTimeout(function () { - document.getElementById('game-area').focus(); - }, 10); - }); - } + // ----- public variables ----- + me.snakeBody = {}; + me.snakeBody["b0"] = new SnakeBlock(); // create snake head + me.snakeBody["b0"].row = config.startRow || 1; + me.snakeBody["b0"].col = config.startCol || 1; + me.snakeBody["b0"].elm = createSnakeElement(); + me.snakeBody["b0"].elmStyle = me.snakeBody["b0"].elm.style; + playingBoard.getBoardContainer().appendChild(me.snakeBody["b0"].elm); + me.snakeBody["b0"].elm.style.left = getLeftPosition(me.snakeBody["b0"]); + me.snakeBody["b0"].elm.style.top = getTopPosition(me.snakeBody["b0"]); + me.snakeBody["b0"].next = me.snakeBody["b0"]; + me.snakeBody["b0"].prev = me.snakeBody["b0"]; - // ----- public variables ----- - me.snakeBody = {}; - me.snakeBody["b0"] = new SnakeBlock(); // create snake head - me.snakeBody["b0"].row = config.startRow || 1; - me.snakeBody["b0"].col = config.startCol || 1; - me.snakeBody["b0"].elm = createSnakeElement(); - me.snakeBody["b0"].elmStyle = me.snakeBody["b0"].elm.style; - playingBoard.getBoardContainer().appendChild(me.snakeBody["b0"].elm); - me.snakeBody["b0"].elm.style.left = getLeftPosition(me.snakeBody["b0"]); - me.snakeBody["b0"].elm.style.top = getTopPosition(me.snakeBody["b0"]); - me.snakeBody["b0"].next = me.snakeBody["b0"]; - me.snakeBody["b0"].prev = me.snakeBody["b0"]; - - me.snakeLength = 1; - me.snakeHead = me.snakeBody["b0"]; - me.snakeTail = me.snakeBody["b0"]; - me.snakeHead.elm.className = me.snakeHead.elm.className.replace(/\bsnake-snakebody-dead\b/, ''); - me.snakeHead.elm.id = "snake-snakehead-alive"; - me.snakeHead.elm.className += " snake-snakebody-alive"; - - // ----- private methods ----- - - function getTopPosition(block) { - const num = block.row * playingBoard.getBlockHeight() - return `${num}px`; - } - function getLeftPosition(block) { - const num = block.col * playingBoard.getBlockWidth() - return `${num}px`; - } + me.snakeLength = 1; + me.snakeHead = me.snakeBody["b0"]; + me.snakeTail = me.snakeBody["b0"]; + me.snakeHead.elm.className = me.snakeHead.elm.className.replace( + /\bsnake-snakebody-dead\b/, + "", + ); + me.snakeHead.elm.id = "snake-snakehead-alive"; + me.snakeHead.elm.className += " snake-snakebody-alive"; - function createSnakeElement() { - const tempNode = document.createElement("div"); - tempNode.className = "snake-snakebody-block"; - tempNode.style.left = "-1000px"; - tempNode.style.top = "-1000px"; - tempNode.style.width = playingBoard.getBlockWidth() + "px"; - tempNode.style.height = playingBoard.getBlockHeight() + "px"; - return tempNode; - } + // ----- private methods ----- - function createBlocks(num) { - let tempBlock; - const tempNode = createSnakeElement(); + function getTopPosition(block) { + const num = block.row * playingBoard.getBlockHeight(); + return `${num}px`; + } + + function getLeftPosition(block) { + const num = block.col * playingBoard.getBlockWidth(); + return `${num}px`; + } + + function createSnakeElement() { + const tempNode = document.createElement("div"); + tempNode.className = "snake-snakebody-block"; + tempNode.style.left = "-1000px"; + tempNode.style.top = "-1000px"; + tempNode.style.width = playingBoard.getBlockWidth() + "px"; + tempNode.style.height = playingBoard.getBlockHeight() + "px"; + return tempNode; + } + + function createBlocks(num) { + let tempBlock; + const tempNode = createSnakeElement(); + + for (let ii = 1; ii < num; ii++) { + tempBlock = new SnakeBlock(); + tempBlock.elm = tempNode.cloneNode(true); + tempBlock.elmStyle = tempBlock.elm.style; + playingBoard.getBoardContainer().appendChild(tempBlock.elm); + blockPool[blockPool.length] = tempBlock; + } - for (let ii = 1; ii < num; ii++) { tempBlock = new SnakeBlock(); - tempBlock.elm = tempNode.cloneNode(true); - tempBlock.elmStyle = tempBlock.elm.style; + tempBlock.elm = tempNode; playingBoard.getBoardContainer().appendChild(tempBlock.elm); blockPool[blockPool.length] = tempBlock; } - tempBlock = new SnakeBlock(); - tempBlock.elm = tempNode; - playingBoard.getBoardContainer().appendChild(tempBlock.elm); - blockPool[blockPool.length] = tempBlock; - } - - function recordScore() { - const highScore = localStorage.jsSnakeHighScore; - if (me.snakeLength > highScore) { - alert('Congratulations! You have beaten your previous high score, which was ' + highScore + '.'); - localStorage.setItem('jsSnakeHighScore', me.snakeLength); + function recordScore() { + const highScore = localStorage[HIGH_SCORE_KEY]; + if (me.snakeLength > highScore) { + alert( + "Congratulations! You have beaten your previous high score, which was " + + highScore + + ".", + ); + localStorage.setItem(HIGH_SCORE_KEY, me.snakeLength); + } } - } - function handleEndCondition(handleFunc) { - recordScore(); - me.snakeHead.elm.style.zIndex = getNextHighestZIndex(me.snakeBody); - me.snakeHead.elm.className = me.snakeHead.elm.className.replace(/\bsnake-snakebody-alive\b/, '') - me.snakeHead.elm.className += " snake-snakebody-dead"; - - isDead = true; - handleFunc(); - } + function handleEndCondition(handleFunc) { + recordScore(); + me.snakeHead.elm.style.zIndex = getNextHighestZIndex(me.snakeBody); + me.snakeHead.elm.className = me.snakeHead.elm.className.replace( + /\bsnake-snakebody-alive\b/, + "", + ); + me.snakeHead.elm.className += " snake-snakebody-dead"; + + isDead = true; + handleFunc(); + } - // ----- public methods ----- + // ----- public methods ----- - me.setPaused = function (val) { - isPaused = val; - }; - me.getPaused = function () { - return isPaused; - }; + me.setPaused = function (val) { + isPaused = val; + }; + me.getPaused = function () { + return isPaused; + }; - /** - * This method is called when a user presses a key. It logs arrow key presses in "currentDirection", which is used when the snake needs to make its next move. - * @method handleArrowKeys - * @param {Number} keyNum A number representing the key that was pressed. - */ - /* + /** + * This method is called when a user presses a key. It logs arrow key presses in "currentDirection", which is used when the snake needs to make its next move. + * @method handleArrowKeys + * @param {Number} keyNum A number representing the key that was pressed. + */ + /* Handles what happens when an arrow key is pressed. Direction explained (0 = up, etc etc) 0 3 1 2 */ - me.handleArrowKeys = function (keyNum) { - if (isDead || (isPaused && !config.premoveOnPause)) { - return; - } - - let directionFound = MOVE_NONE; - - switch (keyNum) { - case 37: - case 65: - directionFound = MOVE_LEFT; - break; - case 38: - case 87: - directionFound = MOVE_UP; - break; - case 39: - case 68: - directionFound = MOVE_RIGHT; - break; - case 40: - case 83: - directionFound = MOVE_DOWN; - break; - } - if (currentDirection !== lastMove) // Allow a queue of 1 premove so you can turn again before the first turn registers - { - preMove = directionFound; - } - if (Math.abs(directionFound - lastMove) !== 2 && (isFirstMove || isPaused) || isFirstGameMove) // Prevent snake from turning 180 degrees - { - currentDirection = directionFound; - isFirstMove = false; - isFirstGameMove = false; - } - }; - - /** - * This method is executed for each move of the snake. It determines where the snake will go and what will happen to it. This method needs to run quickly. - * @method go - */ - me.go = function () { + me.handleArrowKeys = function (keyNum) { + if (isDead || (isPaused && !config.premoveOnPause)) { + return; + } - const oldHead = me.snakeHead, - newHead = me.snakeTail, - grid = playingBoard.grid; // cache grid for quicker lookup + let directionFound = MOVE_NONE; + + switch (keyNum) { + case 37: + case 65: + directionFound = MOVE_LEFT; + break; + case 38: + case 87: + directionFound = MOVE_UP; + break; + case 39: + case 68: + directionFound = MOVE_RIGHT; + break; + case 40: + case 83: + directionFound = MOVE_DOWN; + break; + } + if (currentDirection !== lastMove) { + // Allow a queue of 1 premove so you can turn again before the first turn registers + preMove = directionFound; + } + if (Math.abs(directionFound - lastMove) !== 2 || isFirstGameMove) { + // Prevent snake from turning 180 degrees + currentDirection = directionFound; + isFirstGameMove = false; + } + }; - if (isPaused === true) { - setTimeout(function () { - me.go(); - }, snakeSpeed); - return; - } + /** + * This method is executed for each move of the snake. It determines where the snake will go and what will happen to it. This method needs to run quickly. + * @method go + */ + me.go = function () { + const oldHead = me.snakeHead, + newHead = me.snakeTail, + grid = playingBoard.grid; // cache grid for quicker lookup + + if (isPaused === true) { + setTimeout(function () { + me.go(); + }, snakeSpeed); + return; + } - me.snakeTail = newHead.prev; - me.snakeHead = newHead; + // code to execute if snake is being moved by AI + if (config.moveSnakeWithAI) { + config.moveSnakeWithAI({ + grid, + snakeHead: me.snakeHead, + currentDirection, + isFirstGameMove, + setDirection: me.setDirection, + }); + } - // clear the old board position - if (grid[newHead.row] && grid[newHead.row][newHead.col]) { - grid[newHead.row][newHead.col] = 0; - } + me.snakeTail = newHead.prev; + me.snakeHead = newHead; - if (currentDirection !== MOVE_NONE) { - lastMove = currentDirection; - if (preMove !== MOVE_NONE) // If the user queued up another move after the current one - { - currentDirection = preMove; // Execute that move next time (unless overwritten) - preMove = MOVE_NONE; + // clear the old board position + if (grid[newHead.row] && grid[newHead.row][newHead.col]) { + grid[newHead.row][newHead.col] = 0; } - } - isFirstMove = true; - newHead.col = oldHead.col + columnShift[lastMove]; - newHead.row = oldHead.row + rowShift[lastMove]; - - if (!newHead.elmStyle) { - newHead.elmStyle = newHead.elm.style; - } + if (currentDirection !== MOVE_NONE) { + lastMove = currentDirection; + if (preMove !== MOVE_NONE) { + // If the user queued up another move after the current one + currentDirection = preMove; // Execute that move next time (unless overwritten) + preMove = MOVE_NONE; + } + } - newHead.elmStyle.left = getLeftPosition(newHead); - newHead.elmStyle.top = getTopPosition(newHead); - if (me.snakeLength > 1) { - newHead.elm.id = "snake-snakehead-alive"; - oldHead.elm.id = ""; - } + newHead.col = oldHead.col + columnShift[lastMove]; + newHead.row = oldHead.row + rowShift[lastMove]; + if (!newHead.elmStyle) { + newHead.elmStyle = newHead.elm.style; + } - // check the new spot the snake moved into + newHead.elmStyle.left = getLeftPosition(newHead); + newHead.elmStyle.top = getTopPosition(newHead); + if (me.snakeLength > 1) { + newHead.elm.id = "snake-snakehead-alive"; + oldHead.elm.id = ""; + } - if (grid[newHead.row][newHead.col] === 0) { - grid[newHead.row][newHead.col] = 1; - setTimeout(function () { - me.go(); - }, snakeSpeed); - } else if (grid[newHead.row][newHead.col] > 0) { - me.handleDeath(); - } else if (grid[newHead.row][newHead.col] === playingBoard.getGridFoodValue()) { - grid[newHead.row][newHead.col] = 1; - if (!me.eatFood()) { - me.handleWin(); - return; + // check the new spot the snake moved into + + if (grid[newHead.row][newHead.col] === 0) { + grid[newHead.row][newHead.col] = 1; + setTimeout(function () { + me.go(); + }, snakeSpeed); + } else if (grid[newHead.row][newHead.col] > 0) { + me.handleDeath(); + } else if ( + grid[newHead.row][newHead.col] === playingBoard.getGridFoodValue() + ) { + grid[newHead.row][newHead.col] = 1; + if (!me.eatFood()) { + me.handleWin(); + return; + } + setTimeout(function () { + me.go(); + }, snakeSpeed); } - setTimeout(function () { - me.go(); - }, snakeSpeed); - } - }; + }; - /** - * This method is called when it is determined that the snake has eaten some food. - * @method eatFood - * @return {bool} Whether a new food was able to spawn (true) - * or not (false) after the snake eats food. - */ - me.eatFood = function () { - if (blockPool.length <= growthIncr) { - createBlocks(growthIncr * 2); - } - const blocks = blockPool.splice(0, growthIncr); - - let ii = blocks.length, - index; - prevNode = me.snakeTail; - while (ii--) { - index = "b" + me.snakeLength++; - me.snakeBody[index] = blocks[ii]; - me.snakeBody[index].prev = prevNode; - me.snakeBody[index].elm.className = me.snakeHead.elm.className.replace(/\bsnake-snakebody-dead\b/, '') - me.snakeBody[index].elm.className += " snake-snakebody-alive"; - prevNode.next = me.snakeBody[index]; - prevNode = me.snakeBody[index]; - } - me.snakeTail = me.snakeBody[index]; - me.snakeTail.next = me.snakeHead; - me.snakeHead.prev = me.snakeTail; + /** + * This method is called when it is determined that the snake has eaten some food. + * @method eatFood + * @return {bool} Whether a new food was able to spawn (true) + * or not (false) after the snake eats food. + */ + me.eatFood = function () { + if (blockPool.length <= growthIncr) { + createBlocks(growthIncr * 2); + } + const blocks = blockPool.splice(0, growthIncr); + + let ii = blocks.length, + index; + prevNode = me.snakeTail; + while (ii--) { + index = "b" + me.snakeLength++; + me.snakeBody[index] = blocks[ii]; + me.snakeBody[index].prev = prevNode; + me.snakeBody[index].elm.className = + me.snakeHead.elm.className.replace(/\bsnake-snakebody-dead\b/, ""); + me.snakeBody[index].elm.className += " snake-snakebody-alive"; + prevNode.next = me.snakeBody[index]; + prevNode = me.snakeBody[index]; + } + me.snakeTail = me.snakeBody[index]; + me.snakeTail.next = me.snakeHead; + me.snakeHead.prev = me.snakeTail; - if (!playingBoard.foodEaten()) { - return false; - } + if (!playingBoard.foodEaten()) { + return false; + } - //Checks if the current selected option is that of "Rush" - //If so, "increase" the snake speed - const selectDropDown = document.getElementById("selectMode"); - const selectedOption = selectDropDown.options[selectDropDown.selectedIndex]; + //Checks if the current selected option is that of "Rush" + //If so, "increase" the snake speed + const selectDropDown = document.getElementById("selectMode"); + const selectedOption = + selectDropDown.options[selectDropDown.selectedIndex]; - if (selectedOption.text.localeCompare("Rush") == 0) { - if (snakeSpeed > (MIN_SNAKE_SPEED + RUSH_INCR)) { - snakeSpeed -= RUSH_INCR; + if (selectedOption.text.localeCompare("Rush") == 0) { + if (snakeSpeed > MIN_SNAKE_SPEED + RUSH_INCR) { + snakeSpeed -= RUSH_INCR; + } } - } - return true; - }; + return true; + }; - /** - * This method handles what happens when the snake dies. - * @method handleDeath - */ - me.handleDeath = function () { - //Reset speed - const selectedSpeed = document.getElementById("selectMode").value; - snakeSpeed = parseInt(selectedSpeed); + /** + * This method handles what happens when the snake dies. + * @method handleDeath + */ + me.handleDeath = function () { + //Reset speed + const selectedSpeed = document.getElementById("selectMode").value; + snakeSpeed = parseInt(selectedSpeed); - handleEndCondition(playingBoard.handleDeath); - }; + handleEndCondition(playingBoard.handleDeath); + }; - /** - * This method handles what happens when the snake wins. - * @method handleDeath - */ - me.handleWin = function () { - handleEndCondition(playingBoard.handleWin); - }; + /** + * This method handles what happens when the snake wins. + * @method handleDeath + */ + me.handleWin = function () { + handleEndCondition(playingBoard.handleWin); + }; - /** - * This method sets a flag that lets the snake be alive again. - * @method rebirth - */ - me.rebirth = function () { - isDead = false; - isFirstMove = true; - isFirstGameMove = true; - preMove = MOVE_NONE; - }; + /** + * This method sets a flag that lets the snake be alive again. + * @method rebirth + */ + me.rebirth = function () { + isDead = false; + isFirstGameMove = true; + preMove = MOVE_NONE; + }; - /** - * This method reset the snake so it is ready for a new game. - * @method reset - */ - me.reset = function () { - if (isDead === false) { - return; - } + /** + * This method reset the snake so it is ready for a new game. + * @method reset + */ + me.reset = function () { + if (isDead === false) { + return; + } - const blocks = []; - let curNode = me.snakeHead.next; - let nextNode; + const blocks = []; + let curNode = me.snakeHead.next; + let nextNode; - while (curNode !== me.snakeHead) { - nextNode = curNode.next; - curNode.prev = null; - curNode.next = null; - blocks.push(curNode); - curNode = nextNode; - } - me.snakeHead.next = me.snakeHead; - me.snakeHead.prev = me.snakeHead; - me.snakeTail = me.snakeHead; - me.snakeLength = 1; + while (curNode !== me.snakeHead) { + nextNode = curNode.next; + curNode.prev = null; + curNode.next = null; + blocks.push(curNode); + curNode = nextNode; + } + me.snakeHead.next = me.snakeHead; + me.snakeHead.prev = me.snakeHead; + me.snakeTail = me.snakeHead; + me.snakeLength = 1; + + for (let ii = 0; ii < blocks.length; ii++) { + blocks[ii].elm.style.left = "-1000px"; + blocks[ii].elm.style.top = "-1000px"; + blocks[ii].elm.className = me.snakeHead.elm.className.replace( + /\bsnake-snakebody-dead\b/, + "", + ); + blocks[ii].elm.className += " snake-snakebody-alive"; + } - for (let ii = 0; ii < blocks.length; ii++) { - blocks[ii].elm.style.left = "-1000px"; - blocks[ii].elm.style.top = "-1000px"; - blocks[ii].elm.className = me.snakeHead.elm.className.replace(/\bsnake-snakebody-dead\b/, '') - blocks[ii].elm.className += " snake-snakebody-alive"; - } + blockPool.concat(blocks); + me.snakeHead.elm.className = me.snakeHead.elm.className.replace( + /\bsnake-snakebody-dead\b/, + "", + ); + me.snakeHead.elm.className += " snake-snakebody-alive"; + me.snakeHead.elm.id = "snake-snakehead-alive"; + me.snakeHead.row = config.startRow || 1; + me.snakeHead.col = config.startCol || 1; + me.snakeHead.elm.style.left = getLeftPosition(me.snakeHead); + me.snakeHead.elm.style.top = getTopPosition(me.snakeHead); + }; - blockPool.concat(blocks); - me.snakeHead.elm.className = me.snakeHead.elm.className.replace(/\bsnake-snakebody-dead\b/, '') - me.snakeHead.elm.className += " snake-snakebody-alive"; - me.snakeHead.elm.id = "snake-snakehead-alive"; - me.snakeHead.row = config.startRow || 1; - me.snakeHead.col = config.startCol || 1; - me.snakeHead.elm.style.left = getLeftPosition(me.snakeHead); - me.snakeHead.elm.style.top = getTopPosition(me.snakeHead); - }; + me.getSpeed = () => { + return snakeSpeed; + }; + me.setSpeed = (speed) => { + snakeSpeed = speed; + }; - // --------------------------------------------------------------------- - // Initialize - // --------------------------------------------------------------------- - createBlocks(growthIncr * 2); - }; -})(); + // --------------------------------------------------------------------- + // Initialize + // --------------------------------------------------------------------- + createBlocks(growthIncr * 2); + }; + })(); /** * This class manages the food which the snake will eat. @@ -504,96 +554,101 @@ SNAKE.Snake = SNAKE.Snake || (function () { * @param {Object} config The configuration object for the class. Contains playingBoard (the SNAKE.Board that this food resides in). */ -SNAKE.Food = SNAKE.Food || (function () { - - // ------------------------------------------------------------------------- - // Private static variables and methods - // ------------------------------------------------------------------------- +SNAKE.Food = + SNAKE.Food || + (function () { + // ------------------------------------------------------------------------- + // Private static variables and methods + // ------------------------------------------------------------------------- - let instanceNumber = 0; + let instanceNumber = 0; - function getRandomPosition(x, y) { - return Math.floor(Math.random() * (y + 1 - x)) + x; - } + function getRandomPosition(x, y) { + return Math.floor(Math.random() * (y + 1 - x)) + x; + } - // ------------------------------------------------------------------------- - // Contructor + public and private definitions - // ------------------------------------------------------------------------- + // ------------------------------------------------------------------------- + // Contructor + public and private definitions + // ------------------------------------------------------------------------- - /* + /* config options: playingBoard - the SnakeBoard that this object belongs too. */ - return function (config) { - - if (!config || !config.playingBoard) { - return; - } + return function (config) { + if (!config || !config.playingBoard) { + return; + } - // ----- private variables ----- - - const me = this; - const playingBoard = config.playingBoard; - let fRow, fColumn; - const myId = instanceNumber++; - - const elmFood = document.createElement("div"); - elmFood.setAttribute("id", "snake-food-" + myId); - elmFood.className = "snake-food-block"; - elmFood.style.width = playingBoard.getBlockWidth() + "px"; - elmFood.style.height = playingBoard.getBlockHeight() + "px"; - elmFood.style.left = "-1000px"; - elmFood.style.top = "-1000px"; - playingBoard.getBoardContainer().appendChild(elmFood); - - // ----- public methods ----- - - /** - * @method getFoodElement - * @return {DOM Element} The div the represents the food. - */ - me.getFoodElement = function () { - return elmFood; - }; + // ----- private variables ----- + + const me = this; + const playingBoard = config.playingBoard; + let fRow, fColumn; + const myId = instanceNumber++; + + const elmFood = document.createElement("div"); + elmFood.setAttribute("id", "snake-food-" + myId); + elmFood.className = "snake-food-block"; + elmFood.style.width = playingBoard.getBlockWidth() + "px"; + elmFood.style.height = playingBoard.getBlockHeight() + "px"; + elmFood.style.left = "-1000px"; + elmFood.style.top = "-1000px"; + playingBoard.getBoardContainer().appendChild(elmFood); + + // ----- public methods ----- + + /** + * @method getFoodElement + * @return {DOM Element} The div the represents the food. + */ + me.getFoodElement = function () { + return elmFood; + }; - /** - * Randomly places the food onto an available location on the playing board. - * @method randomlyPlaceFood - * @return {bool} Whether a food was able to spawn (true) or not (false). - */ - me.randomlyPlaceFood = function () { - // if there exist some food, clear its presence from the board - if (playingBoard.grid[fRow] && playingBoard.grid[fRow][fColumn] === playingBoard.getGridFoodValue()) { - playingBoard.grid[fRow][fColumn] = 0; - } + /** + * Randomly places the food onto an available location on the playing board. + * @method randomlyPlaceFood + * @return {bool} Whether a food was able to spawn (true) or not (false). + */ + me.randomlyPlaceFood = function () { + // if there exist some food, clear its presence from the board + if ( + playingBoard.grid[fRow] && + playingBoard.grid[fRow][fColumn] === playingBoard.getGridFoodValue() + ) { + playingBoard.grid[fRow][fColumn] = 0; + } - let row = 0, col = 0, numTries = 0; + let row = 0, + col = 0, + numTries = 0; - const maxRows = playingBoard.grid.length - 1; - const maxCols = playingBoard.grid[0].length - 1; + const maxRows = playingBoard.grid.length - 1; + const maxCols = playingBoard.grid[0].length - 1; - while (playingBoard.grid[row][col] !== 0) { - row = getRandomPosition(1, maxRows); - col = getRandomPosition(1, maxCols); + while (playingBoard.grid[row][col] !== 0) { + row = getRandomPosition(1, maxRows); + col = getRandomPosition(1, maxCols); - // in some cases there may not be any room to put food anywhere - // instead of freezing, exit out (and return false to indicate - // that the player beat the game) - numTries++; - if (numTries > 20000) { - return false; + // in some cases there may not be any room to put food anywhere + // instead of freezing, exit out (and return false to indicate + // that the player beat the game) + numTries++; + if (numTries > 20000) { + return false; + } } - } - playingBoard.grid[row][col] = playingBoard.getGridFoodValue(); - fRow = row; - fColumn = col; - elmFood.style.top = row * playingBoard.getBlockHeight() + "px"; - elmFood.style.left = col * playingBoard.getBlockWidth() + "px"; - return true; + playingBoard.grid[row][col] = playingBoard.getGridFoodValue(); + fRow = row; + fColumn = col; + elmFood.style.top = row * playingBoard.getBlockHeight() + "px"; + elmFood.style.left = col * playingBoard.getBlockWidth() + "px"; + return true; + }; }; - }; -})(); + })(); /** * This class manages playing board for the game. @@ -603,557 +658,733 @@ SNAKE.Food = SNAKE.Food || (function () { * @param {Object} config The configuration object for the class. Set fullScreen equal to true if you want the game to take up the full screen, otherwise, set the top, left, width and height parameters. */ -SNAKE.Board = SNAKE.Board || (function () { - - // ------------------------------------------------------------------------- - // Private static variables and methods - // ------------------------------------------------------------------------- - - let instanceNumber = 0; - - // this function is adapted from the example at http://greengeckodesign.com/blog/2007/07/get-highest-z-index-in-javascript.html - function getNextHighestZIndex(myObj) { - let highestIndex = 0, - currentIndex = 0, - ii; - for (ii in myObj) { - if (myObj[ii].elm.currentStyle) { - currentIndex = parseFloat(myObj[ii].elm.style["z-index"], 10); - } else if (window.getComputedStyle) { - currentIndex = parseFloat(document.defaultView.getComputedStyle(myObj[ii].elm, null).getPropertyValue("z-index"), 10); - } - if (!isNaN(currentIndex) && currentIndex > highestIndex) { - highestIndex = currentIndex; +SNAKE.Board = + SNAKE.Board || + (function () { + // ------------------------------------------------------------------------- + // Private static variables and methods + // ------------------------------------------------------------------------- + + let instanceNumber = 0; + + // this function is adapted from the example at http://greengeckodesign.com/blog/2007/07/get-highest-z-index-in-javascript.html + function getNextHighestZIndex(myObj) { + let highestIndex = 0, + currentIndex = 0, + ii; + for (ii in myObj) { + if (myObj[ii].elm.currentStyle) { + currentIndex = parseFloat(myObj[ii].elm.style["z-index"], 10); + } else if (window.getComputedStyle) { + currentIndex = parseFloat( + document.defaultView + .getComputedStyle(myObj[ii].elm, null) + .getPropertyValue("z-index"), + 10, + ); + } + if (!isNaN(currentIndex) && currentIndex > highestIndex) { + highestIndex = currentIndex; + } } + return highestIndex + 1; } - return (highestIndex + 1); - } - /* + /* This function returns the width of the available screen real estate that we have */ - function getClientWidth() { - let myWidth = 0; - if (typeof window.innerWidth === "number") { - myWidth = window.innerWidth;//Non-IE - } else if (document.documentElement && (document.documentElement.clientWidth || document.documentElement.clientHeight)) { - myWidth = document.documentElement.clientWidth;//IE 6+ in 'standards compliant mode' - } else if (document.body && (document.body.clientWidth || document.body.clientHeight)) { - myWidth = document.body.clientWidth;//IE 4 compatible + function getClientWidth() { + let myWidth = 0; + if (typeof window.innerWidth === "number") { + myWidth = window.innerWidth; //Non-IE + } else if ( + document.documentElement && + (document.documentElement.clientWidth || + document.documentElement.clientHeight) + ) { + myWidth = document.documentElement.clientWidth; //IE 6+ in 'standards compliant mode' + } else if ( + document.body && + (document.body.clientWidth || document.body.clientHeight) + ) { + myWidth = document.body.clientWidth; //IE 4 compatible + } + return myWidth; } - return myWidth; - } - /* + /* This function returns the height of the available screen real estate that we have */ - function getClientHeight() { - let myHeight = 0; - if (typeof window.innerHeight === "number") { - myHeight = window.innerHeight;//Non-IE - } else if (document.documentElement && (document.documentElement.clientWidth || document.documentElement.clientHeight)) { - myHeight = document.documentElement.clientHeight;//IE 6+ in 'standards compliant mode' - } else if (document.body && (document.body.clientWidth || document.body.clientHeight)) { - myHeight = document.body.clientHeight;//IE 4 compatible + function getClientHeight() { + let myHeight = 0; + if (typeof window.innerHeight === "number") { + myHeight = window.innerHeight; //Non-IE + } else if ( + document.documentElement && + (document.documentElement.clientWidth || + document.documentElement.clientHeight) + ) { + myHeight = document.documentElement.clientHeight; //IE 6+ in 'standards compliant mode' + } else if ( + document.body && + (document.body.clientWidth || document.body.clientHeight) + ) { + myHeight = document.body.clientHeight; //IE 4 compatible + } + return myHeight; } - return myHeight; - } - - // ------------------------------------------------------------------------- - // Contructor + public and private definitions - // ------------------------------------------------------------------------- - - return function (inputConfig) { - - // --- private variables --- - const me = this; - const myId = instanceNumber++; - const config = inputConfig || {}; - const MAX_BOARD_COLS = 250; - const MAX_BOARD_ROWS = 250; - const blockWidth = 20; - const blockHeight = 20; - const GRID_FOOD_VALUE = -1; // the value of a spot on the board that represents snake food; MUST BE NEGATIVE - - let myFood, - mySnake, - boardState = 1, // 0: in active, 1: awaiting game start, 2: playing game - myKeyListener, - myWindowListener, - isPaused = false;//note: both the board and the snake can be paused - - // Board components - let elmContainer, - elmPlayingField, - elmAboutPanel, - elmLengthPanel, - elmHighscorePanel, - elmWelcome, - elmTryAgain, - elmWin, - elmPauseScreen; - - // --- public variables --- - me.grid = []; - - // --------------------------------------------------------------------- - // private functions - // --------------------------------------------------------------------- - - function createBoardElements() { - elmPlayingField = document.createElement("div"); - elmPlayingField.setAttribute("id", "playingField"); - elmPlayingField.className = "snake-playing-field"; - - SNAKE.addEventListener(elmPlayingField, "click", function () { - elmContainer.focus(); - }, false); - - elmPauseScreen = document.createElement("div"); - elmPauseScreen.className = "snake-pause-screen"; - elmPauseScreen.innerHTML = "
[Paused]

Press [space] to unpause.

"; - - elmAboutPanel = document.createElement("div"); - elmAboutPanel.className = "snake-panel-component"; - elmAboutPanel.innerHTML = "more patorjk.com apps - source code - pat's youtube"; - - elmLengthPanel = document.createElement("div"); - elmLengthPanel.className = "snake-panel-component"; - elmLengthPanel.innerHTML = "Length: 1"; - - elmHighscorePanel = document.createElement("div"); - elmHighscorePanel.className = "snake-panel-component"; - elmHighscorePanel.innerHTML = "Highscore: " + (localStorage.jsSnakeHighScore || 0); - - elmWelcome = createWelcomeElement(); - elmTryAgain = createTryAgainElement(); - elmWin = createWinElement(); - - SNAKE.addEventListener(elmContainer, "keyup", function (evt) { - if (!evt) evt = window.event; - evt.cancelBubble = true; - if (evt.stopPropagation) { - evt.stopPropagation(); - } - if (evt.preventDefault) { - evt.preventDefault(); - } - return false; - }, false); - - elmContainer.className = "snake-game-container"; - elmPauseScreen.style.zIndex = 10000; - elmContainer.appendChild(elmPauseScreen); - elmContainer.appendChild(elmPlayingField); - elmContainer.appendChild(elmAboutPanel); - elmContainer.appendChild(elmLengthPanel); - elmContainer.appendChild(elmHighscorePanel); - elmContainer.appendChild(elmWelcome); - elmContainer.appendChild(elmTryAgain); - elmContainer.appendChild(elmWin); - - mySnake = new SNAKE.Snake({playingBoard: me, startRow: 2, startCol: 2, premoveOnPause: config.premoveOnPause}); - myFood = new SNAKE.Food({playingBoard: me}); - - elmWelcome.style.zIndex = 1000; - } + // ------------------------------------------------------------------------- + // Contructor + public and private definitions + // ------------------------------------------------------------------------- + + return function (inputConfig) { + // --- private variables --- + const me = this; + const myId = instanceNumber++; + const config = inputConfig || {}; + const MAX_BOARD_COLS = 250; + const MAX_BOARD_ROWS = 250; + const blockWidth = 20; + const blockHeight = 20; + const GRID_FOOD_VALUE = -1; // the value of a spot on the board that represents snake food; MUST BE NEGATIVE + + // defaults + if (!config.onLengthUpdate) { + config.onLengthUpdate = () => {}; + } - function maxBoardWidth() { - return MAX_BOARD_COLS * me.getBlockWidth(); - } + if (!config.onPauseToggle) { + config.onPauseToggle = () => {}; + } + if (!config.onWin) { + config.onWin = () => {}; + } + if (!config.onDeath) { + config.onDeath = () => {}; + } - function maxBoardHeight() { - return MAX_BOARD_ROWS * me.getBlockHeight(); - } + let myFood, + mySnake, + boardState = 1, // 0: in active, 1: awaiting game start, 2: playing game + myKeyListener, + myWindowListener, + isPaused = false; //note: both the board and the snake can be paused + + // Board components + let elmContainer, + elmPlayingField, + elmAboutPanel, + elmLengthPanel, + elmHighscorePanel, + elmWelcome, + elmTryAgain, + elmWin, + elmPauseScreen; + + // --- public variables --- + me.grid = []; - function createWelcomeElement() { - const tmpElm = document.createElement("div"); - tmpElm.id = "sbWelcome" + myId; - tmpElm.className = "snake-welcome-dialog"; + // --------------------------------------------------------------------- + // private functions + // --------------------------------------------------------------------- - const welcomeTxt = document.createElement("div"); - let fullScreenText = ""; - if (config.fullScreen) { - fullScreenText = "On Windows, press F11 to play in Full Screen mode."; + function getStartRow() { + return config.startRow || 2; } - welcomeTxt.innerHTML = "JavaScript Snake

Use the arrow keys on your keyboard to play the game. " + fullScreenText + "

"; - const welcomeStart = document.createElement("button"); - welcomeStart.appendChild(document.createTextNode("Play Game")); - - const loadGame = function () { - SNAKE.removeEventListener(window, "keyup", kbShortcut, false); - tmpElm.style.display = "none"; - me.setBoardState(1); - me.getBoardContainer().focus(); - }; - const kbShortcut = function (evt) { - if (!evt) evt = window.event; - const keyNum = (evt.which) ? evt.which : evt.keyCode; - if (keyNum === 32 || keyNum === 13) { - loadGame(); - } - }; - - SNAKE.addEventListener(window, "keyup", kbShortcut, false); - SNAKE.addEventListener(welcomeStart, "click", loadGame, false); + function getStartCol() { + return config.startCol || 2; + } - tmpElm.appendChild(welcomeTxt); - tmpElm.appendChild(welcomeStart); - return tmpElm; - } + function createBoardElements() { + elmPlayingField = document.createElement("div"); + elmPlayingField.setAttribute("id", "playingField"); + elmPlayingField.className = "snake-playing-field"; + + SNAKE.addEventListener( + elmPlayingField, + "click", + function () { + elmContainer.focus(); + }, + false, + ); + + elmPauseScreen = document.createElement("div"); + elmPauseScreen.className = "snake-pause-screen"; + elmPauseScreen.innerHTML = + "
[Paused]

Press [space] to unpause.

"; + + elmAboutPanel = document.createElement("div"); + elmAboutPanel.className = "snake-panel-component"; + elmAboutPanel.innerHTML = + "more patorjk.com apps - source code - pat's youtube"; + + elmLengthPanel = document.createElement("div"); + elmLengthPanel.className = "snake-panel-component"; + elmLengthPanel.innerHTML = "Length: 1"; + + elmHighscorePanel = document.createElement("div"); + elmHighscorePanel.className = "snake-panel-component"; + elmHighscorePanel.innerHTML = + "Highscore: " + (localStorage[HIGH_SCORE_KEY] || 0); + + elmWelcome = createWelcomeElement(); + elmTryAgain = createTryAgainElement(); + elmWin = createWinElement(); + + SNAKE.addEventListener( + elmContainer, + "keyup", + function (evt) { + if (!evt) evt = window.event; + evt.cancelBubble = true; + if (evt.stopPropagation) { + evt.stopPropagation(); + } + if (evt.preventDefault) { + evt.preventDefault(); + } + return false; + }, + false, + ); + + elmContainer.className = "snake-game-container"; + + elmPauseScreen.style.zIndex = 10000; + elmContainer.appendChild(elmPauseScreen); + elmContainer.appendChild(elmPlayingField); + elmContainer.appendChild(elmAboutPanel); + elmContainer.appendChild(elmLengthPanel); + elmContainer.appendChild(elmHighscorePanel); + elmContainer.appendChild(elmWelcome); + elmContainer.appendChild(elmTryAgain); + elmContainer.appendChild(elmWin); + + mySnake = new SNAKE.Snake({ + playingBoard: me, + startRow: getStartRow(), + startCol: getStartCol(), + premoveOnPause: config.premoveOnPause, + moveSnakeWithAI: config.moveSnakeWithAI, + }); + myFood = new SNAKE.Food({ playingBoard: me }); + + elmWelcome.style.zIndex = 1000; + } - function createGameEndElement(message, elmId, elmClassName) { - const tmpElm = document.createElement("div"); - tmpElm.id = elmId + myId; - tmpElm.className = elmClassName; + function maxBoardWidth() { + return MAX_BOARD_COLS * me.getBlockWidth(); + } - const gameEndTxt = document.createElement("div"); - gameEndTxt.innerHTML = "JavaScript Snake

" + message + "

"; - const gameEndStart = document.createElement("button"); - gameEndStart.appendChild(document.createTextNode("Play Again?")); + function maxBoardHeight() { + return MAX_BOARD_ROWS * me.getBlockHeight(); + } - const reloadGame = function () { - tmpElm.style.display = "none"; - me.resetBoard(); - me.setBoardState(1); - me.getBoardContainer().focus(); - }; + function createWelcomeElement() { + const tmpElm = document.createElement("div"); + tmpElm.id = "sbWelcome" + myId; + tmpElm.className = "snake-welcome-dialog"; - const kbGameEndShortcut = function (evt) { - if (boardState !== 0 || tmpElm.style.display !== "block") { - return; + const welcomeTxt = document.createElement("div"); + let fullScreenText = ""; + if (config.fullScreen) { + fullScreenText = "On Windows, press F11 to play in Full Screen mode."; } - if (!evt) evt = window.event; - const keyNum = (evt.which) ? evt.which : evt.keyCode; - if (keyNum === 32 || keyNum === 13) { - reloadGame(); - } - }; - SNAKE.addEventListener(window, "keyup", kbGameEndShortcut, true); - - SNAKE.addEventListener(gameEndStart, "click", reloadGame, false); - tmpElm.appendChild(gameEndTxt); - tmpElm.appendChild(gameEndStart); - return tmpElm; - } + welcomeTxt.innerHTML = + "JavaScript Snake

Use the arrow keys on your keyboard to play the game. " + + fullScreenText + + "

"; + const welcomeStart = document.createElement("button"); + welcomeStart.appendChild(document.createTextNode("Play Game")); + + const loadGame = function () { + SNAKE.removeEventListener(window, "keyup", kbShortcut, false); + tmpElm.style.display = "none"; + me.setBoardState(BOARD_READY); + me.getBoardContainer().focus(); + }; + + const kbShortcut = function (evt) { + if (!evt) evt = window.event; + const keyNum = evt.which ? evt.which : evt.keyCode; + if (keyNum === 32 || keyNum === 13) { + loadGame(); + } + }; - function createTryAgainElement() { - return createGameEndElement("You died :(", "sbTryAgain", "snake-try-again-dialog"); - } + SNAKE.addEventListener(window, "keyup", kbShortcut, false); + SNAKE.addEventListener(welcomeStart, "click", loadGame, false); - function createWinElement() { - return createGameEndElement("You win! :D", "sbWin", "snake-win-dialog"); - } + tmpElm.appendChild(welcomeTxt); + tmpElm.appendChild(welcomeStart); + return tmpElm; + } - function handleEndCondition(elmDialog) { - const index = Math.max(getNextHighestZIndex(mySnake.snakeBody), getNextHighestZIndex({tmp: {elm: myFood.getFoodElement()}})); - elmContainer.removeChild(elmDialog); - elmContainer.appendChild(elmDialog); - elmDialog.style.zIndex = index; - elmDialog.style.display = "block"; - me.setBoardState(0); - } + function createGameEndElement(message, elmId, elmClassName) { + const tmpElm = document.createElement("div"); + tmpElm.id = elmId + myId; + tmpElm.className = elmClassName; + + const gameEndTxt = document.createElement("div"); + gameEndTxt.innerHTML = "JavaScript Snake

" + message + "

"; + const gameEndStart = document.createElement("button"); + gameEndStart.appendChild(document.createTextNode("Play Again?")); + + const reloadGame = function () { + tmpElm.style.display = "none"; + me.resetBoard(); + me.setBoardState(BOARD_READY); + me.getBoardContainer().focus(); + }; + + const kbGameEndShortcut = function (evt) { + if (boardState !== 0 || tmpElm.style.display !== "block") { + return; + } + if (!evt) evt = window.event; + const keyNum = evt.which ? evt.which : evt.keyCode; + if (keyNum === 32 || keyNum === 13) { + reloadGame(); + } + }; + SNAKE.addEventListener(window, "keyup", kbGameEndShortcut, true); - // --------------------------------------------------------------------- - // public functions - // --------------------------------------------------------------------- - - me.setPaused = function (val) { - isPaused = val; - mySnake.setPaused(val); - if (isPaused) { - elmPauseScreen.style.display = "block"; - } else { - elmPauseScreen.style.display = "none"; + SNAKE.addEventListener(gameEndStart, "click", reloadGame, false); + tmpElm.appendChild(gameEndTxt); + tmpElm.appendChild(gameEndStart); + return tmpElm; } - }; - me.getPaused = function () { - return isPaused; - }; - /** - * Resets the playing board for a new game. - * @method resetBoard - */ - me.resetBoard = function () { - SNAKE.removeEventListener(elmContainer, "keydown", myKeyListener, false); - SNAKE.removeEventListener(elmContainer, "visibilitychange", myWindowListener, false); - mySnake.reset(); - elmLengthPanel.innerHTML = "Length: 1"; - me.setupPlayingField(); - }; - /** - * Gets the current state of the playing board. There are 3 states: 0 - Welcome or Try Again dialog is present. 1 - User has pressed "Start Game" on the Welcome or Try Again dialog but has not pressed an arrow key to move the snake. 2 - The game is in progress and the snake is moving. - * @method getBoardState - * @return {Number} The state of the board. - */ - me.getBoardState = function () { - return boardState; - }; - /** - * Sets the current state of the playing board. There are 3 states: 0 - Welcome or Try Again dialog is present. 1 - User has pressed "Start Game" on the Welcome or Try Again dialog but has not pressed an arrow key to move the snake. 2 - The game is in progress and the snake is moving. - * @method setBoardState - * @param {Number} state The state of the board. - */ - me.setBoardState = function (state) { - boardState = state; - }; - /** - * @method getGridFoodValue - * @return {Number} A number that represents food on a number representation of the playing board. - */ - me.getGridFoodValue = function () { - return GRID_FOOD_VALUE; - }; - /** - * @method getPlayingFieldElement - * @return {DOM Element} The div representing the playing field (this is where the snake can move). - */ - me.getPlayingFieldElement = function () { - return elmPlayingField; - }; - /** - * @method setBoardContainer - * @param {DOM Element or String} myContainer Sets the container element for the game. - */ - me.setBoardContainer = function (myContainer) { - if (typeof myContainer === "string") { - myContainer = document.getElementById(myContainer); - } - if (myContainer === elmContainer) { - return; + function createTryAgainElement() { + return createGameEndElement( + "You died :(", + "sbTryAgain", + "snake-try-again-dialog", + ); } - elmContainer = myContainer; - elmPlayingField = null; - me.setupPlayingField(); - }; - /** - * @method getBoardContainer - * @return {DOM Element} - */ - me.getBoardContainer = function () { - return elmContainer; - }; - /** - * @method getBlockWidth - * @return {Number} - */ - me.getBlockWidth = function () { - return blockWidth; - }; - /** - * @method getBlockHeight - * @return {Number} - */ - me.getBlockHeight = function () { - return blockHeight; - }; - /** - * Sets up the playing field. - * @method setupPlayingField - */ - me.setupPlayingField = function () { - - if (!elmPlayingField) { - createBoardElements(); - } // create playing field - - // calculate width of our game container - let cWidth, cHeight; - let cTop, cLeft; - if (config.fullScreen === true) { - cTop = 0; - cLeft = 0; - cWidth = getClientWidth() - 20; - cHeight = getClientHeight() - 20; - - } else { - cTop = config.top; - cLeft = config.left; - cWidth = config.width; - cHeight = config.height; + function createWinElement() { + return createGameEndElement("You win! :D", "sbWin", "snake-win-dialog"); } - // define the dimensions of the board and playing field - const wEdgeSpace = me.getBlockWidth() * 2 + (cWidth % me.getBlockWidth()); - const fWidth = Math.min(maxBoardWidth() - wEdgeSpace, cWidth - wEdgeSpace); - const hEdgeSpace = me.getBlockHeight() * 3 + (cHeight % me.getBlockHeight()); - const fHeight = Math.min(maxBoardHeight() - hEdgeSpace, cHeight - hEdgeSpace); - - elmContainer.style.left = cLeft + "px"; - elmContainer.style.top = cTop + "px"; - elmContainer.style.width = cWidth + "px"; - elmContainer.style.height = cHeight + "px"; - elmPlayingField.style.left = me.getBlockWidth() + "px"; - elmPlayingField.style.top = me.getBlockHeight() + "px"; - elmPlayingField.style.width = fWidth + "px"; - elmPlayingField.style.height = fHeight + "px"; - - // the math for this will need to change depending on font size, padding, etc - // assuming height of 14 (font size) + 8 (padding) - const bottomPanelHeight = hEdgeSpace - me.getBlockHeight(); - const pLabelTop = me.getBlockHeight() + fHeight + Math.round((bottomPanelHeight - 30) / 2) + "px"; - - elmAboutPanel.style.top = pLabelTop; - elmAboutPanel.style.width = "450px"; - elmAboutPanel.style.left = Math.round(cWidth / 2) - Math.round(450 / 2) + "px"; - - elmLengthPanel.style.top = pLabelTop; - elmLengthPanel.style.left = 30 + "px"; - - elmHighscorePanel.style.top = pLabelTop; - elmHighscorePanel.style.left = cWidth - 140 + "px"; - - // if width is too narrow, hide the about panel - if (cWidth < 700) { - elmAboutPanel.style.display = "none"; - } else { - elmAboutPanel.style.display = "block"; + function handleEndCondition(elmDialog) { + const index = Math.max( + getNextHighestZIndex(mySnake.snakeBody), + getNextHighestZIndex({ tmp: { elm: myFood.getFoodElement() } }), + ); + elmContainer.removeChild(elmDialog); + elmContainer.appendChild(elmDialog); + elmDialog.style.zIndex = index; + elmDialog.style.display = "block"; + me.setBoardState(BOARD_NOT_READY); } - me.grid = []; - const numBoardCols = fWidth / me.getBlockWidth() + 2; - const numBoardRows = fHeight / me.getBlockHeight() + 2; - - for (let row = 0; row < numBoardRows; row++) { - me.grid[row] = []; - for (let col = 0; col < numBoardCols; col++) { - if (col === 0 || row === 0 || col === (numBoardCols - 1) || row === (numBoardRows - 1)) { - me.grid[row][col] = 1; // an edge - } else { - me.grid[row][col] = 0; // empty space - } + // --------------------------------------------------------------------- + // public functions + // --------------------------------------------------------------------- + + me.setPaused = function (val) { + isPaused = val; + mySnake.setPaused(val); + if (isPaused) { + elmPauseScreen.style.display = "block"; + } else { + elmPauseScreen.style.display = "none"; } - } - - myFood.randomlyPlaceFood(); - - myKeyListener = function (evt) { - if (!evt) evt = window.event; - const keyNum = (evt.which) ? evt.which : evt.keyCode; + config.onPauseToggle(isPaused); + }; + me.getPaused = function () { + return isPaused; + }; - if (me.getBoardState() === 1) { - if (!(keyNum >= 37 && keyNum <= 40) && !(keyNum === 87 || keyNum === 65 || keyNum === 83 || keyNum === 68)) { - return; - } // if not an arrow key, leave + /** + * Resets the playing board for a new game. + * @method resetBoard + */ + me.resetBoard = function () { + SNAKE.removeEventListener( + elmContainer, + "keydown", + myKeyListener, + false, + ); + SNAKE.removeEventListener( + elmContainer, + "visibilitychange", + myWindowListener, + false, + ); + mySnake.reset(); + config.onLengthUpdate(1); + elmLengthPanel.innerHTML = "Length: 1"; + me.setupPlayingField(); + }; + /** + * Gets the current state of the playing board. There are 3 states: 0 - Welcome or Try Again dialog is present. 1 - User has pressed "Start Game" on the Welcome or Try Again dialog but has not pressed an arrow key to move the snake. 2 - The game is in progress and the snake is moving. + * @method getBoardState + * @return {Number} The state of the board. + */ + me.getBoardState = function () { + return boardState; + }; + /** + * Sets the current state of the playing board. There are 3 states: 0 - Welcome or Try Again dialog is present. 1 - User has pressed "Start Game" on the Welcome or Try Again dialog but has not pressed an arrow key to move the snake. 2 - The game is in progress and the snake is moving. + * @method setBoardState + * @param {Number} state The state of the board. + */ + me.setBoardState = function (state) { + boardState = state; + }; + /** + * @method getGridFoodValue + * @return {Number} A number that represents food on a number representation of the playing board. + */ + me.getGridFoodValue = function () { + return GRID_FOOD_VALUE; + }; + /** + * @method getPlayingFieldElement + * @return {DOM Element} The div representing the playing field (this is where the snake can move). + */ + me.getPlayingFieldElement = function () { + return elmPlayingField; + }; + /** + * @method setBoardContainer + * @param {DOM Element or String} myContainer Sets the container element for the game. + */ + me.setBoardContainer = function (myContainer) { + if (typeof myContainer === "string") { + myContainer = document.getElementById(myContainer); + } + if (myContainer === elmContainer) { + return; + } + elmContainer = myContainer; + elmPlayingField = null; - // This removes the listener added at the #listenerX line - SNAKE.removeEventListener(elmContainer, "keydown", myKeyListener, false); - SNAKE.removeEventListener(elmContainer, "visibilitychange", myWindowListener, false); + me.setupPlayingField(); + }; + /** + * @method getBoardContainer + * @return {DOM Element} + */ + me.getBoardContainer = function () { + return elmContainer; + }; + /** + * @method getBlockWidth + * @return {Number} + */ + me.getBlockWidth = function () { + return blockWidth; + }; + /** + * @method getBlockHeight + * @return {Number} + */ + me.getBlockHeight = function () { + return blockHeight; + }; + /** + * Sets up the playing field. + * @method setupPlayingField + */ + me.setupPlayingField = function () { + if (!elmPlayingField) { + createBoardElements(); + } // create playing field + + // calculate width of our game container + let cWidth, cHeight; + let cTop, cLeft; + if (config.fullScreen === true) { + cTop = 0; + cLeft = 0; + cWidth = getClientWidth() - 20; + cHeight = getClientHeight() - 20; + } else { + cTop = config.top; + cLeft = config.left; + cWidth = config.width; + cHeight = config.height; + } - myKeyListener = function (evt) { - if (!evt) evt = window.event; - const keyNum = (evt.which) ? evt.which : evt.keyCode; + // define the dimensions of the board and playing field + const wEdgeSpace = + me.getBlockWidth() * 2 + (cWidth % me.getBlockWidth()); + const fWidth = Math.min( + maxBoardWidth() - wEdgeSpace, + cWidth - wEdgeSpace, + ); + const hEdgeSpace = + me.getBlockHeight() * 3 + (cHeight % me.getBlockHeight()); + const fHeight = Math.min( + maxBoardHeight() - hEdgeSpace, + cHeight - hEdgeSpace, + ); + + elmContainer.style.left = cLeft + "px"; + elmContainer.style.top = cTop + "px"; + elmContainer.style.width = cWidth + "px"; + elmContainer.style.height = cHeight + "px"; + elmPlayingField.style.left = me.getBlockWidth() + "px"; + elmPlayingField.style.top = me.getBlockHeight() + "px"; + elmPlayingField.style.width = fWidth + "px"; + elmPlayingField.style.height = fHeight + "px"; + + // the math for this will need to change depending on font size, padding, etc + // assuming height of 14 (font size) + 8 (padding) + const bottomPanelHeight = hEdgeSpace - me.getBlockHeight(); + const pLabelTop = + me.getBlockHeight() + + fHeight + + Math.round((bottomPanelHeight - 30) / 2) + + "px"; + + elmAboutPanel.style.top = pLabelTop; + elmAboutPanel.style.width = "450px"; + elmAboutPanel.style.left = + Math.round(cWidth / 2) - Math.round(450 / 2) + "px"; + + elmLengthPanel.style.top = pLabelTop; + elmLengthPanel.style.left = 30 + "px"; + + elmHighscorePanel.style.top = pLabelTop; + elmHighscorePanel.style.left = cWidth - 140 + "px"; + + // if width is too narrow, hide the about panel + if (cWidth < 700) { + elmAboutPanel.style.display = "none"; + } else { + elmAboutPanel.style.display = "block"; + } - //console.log(keyNum); - if (keyNum === 32) { - if (me.getBoardState() != 0) - me.setPaused(!me.getPaused()); + me.grid = []; + const numBoardCols = fWidth / me.getBlockWidth() + 2; + const numBoardRows = fHeight / me.getBlockHeight() + 2; + + for (let row = 0; row < numBoardRows; row++) { + me.grid[row] = []; + for (let col = 0; col < numBoardCols; col++) { + if ( + col === 0 || + row === 0 || + col === numBoardCols - 1 || + row === numBoardRows - 1 + ) { + me.grid[row][col] = 1; // an edge + } else { + me.grid[row][col] = 0; // empty space } - + } + } + me.grid[getStartRow()][getStartCol()] = 1; // snake head + + myFood.randomlyPlaceFood(); + config.onLengthUpdate(1); + + myKeyListener = function (evt) { + if (!evt) evt = window.event; + const keyNum = evt.which ? evt.which : evt.keyCode; + + if (me.getBoardState() === BOARD_READY) { + if ( + !(keyNum >= 37 && keyNum <= 40) && + !( + keyNum === 87 || + keyNum === 65 || + keyNum === 83 || + keyNum === 68 + ) + ) { + return; + } // if not an arrow key, leave + + // This removes the listener added at the #listenerX line + SNAKE.removeEventListener( + elmContainer, + "keydown", + myKeyListener, + false, + ); + SNAKE.removeEventListener( + elmContainer, + "visibilitychange", + myWindowListener, + false, + ); + + myKeyListener = function (evt) { + if (!evt) evt = window.event; + const keyNum = evt.which ? evt.which : evt.keyCode; + + if (keyNum === 32) { + if (me.getBoardState() != BOARD_NOT_READY) + me.setPaused(!me.getPaused()); + } + + mySnake.handleArrowKeys(keyNum); + + evt.cancelBubble = true; + if (evt.stopPropagation) { + evt.stopPropagation(); + } + if (evt.preventDefault) { + evt.preventDefault(); + } + return false; + }; + + //listener for pausing the game if user change tab or minimize the browser window + document.addEventListener("visibilitychange", () => { + if (document.visibilityState === "hidden") { + if (me.getBoardState() != BOARD_NOT_READY && !me.getPaused()) + me.setPaused(true); + } + }); + + SNAKE.addEventListener( + elmContainer, + "keydown", + myKeyListener, + false, + ); + SNAKE.addEventListener( + elmContainer, + "visibilitychange", + myWindowListener, + false, + ); + + mySnake.rebirth(); mySnake.handleArrowKeys(keyNum); + me.setBoardState(BOARD_IN_PLAY); // start the game! + mySnake.go(); + } - evt.cancelBubble = true; - if (evt.stopPropagation) { - evt.stopPropagation(); - } - if (evt.preventDefault) { - evt.preventDefault(); - } - return false; - }; - - //listener for pausing the game if user change tab or minimize the browser window - document.addEventListener("visibilitychange", () => { - if (document.visibilityState === 'hidden') { - if (me.getBoardState() != 0 && !me.getPaused()) - me.setPaused(true); - } - }); + evt.cancelBubble = true; + if (evt.stopPropagation) { + evt.stopPropagation(); + } + if (evt.preventDefault) { + evt.preventDefault(); + } + return false; + }; + // Search for #listenerX to see where this is removed + if (!config.moveSnakeWithAI) { SNAKE.addEventListener(elmContainer, "keydown", myKeyListener, false); - SNAKE.addEventListener(elmContainer, "visibilitychange", myWindowListener, false); - - mySnake.rebirth(); - mySnake.handleArrowKeys(keyNum); - me.setBoardState(2); // start the game! - mySnake.go(); + SNAKE.addEventListener( + elmContainer, + "visibilitychange", + myWindowListener, + false, + ); } + }; - evt.cancelBubble = true; - if (evt.stopPropagation) { - evt.stopPropagation(); + /** + * This method is called when the snake has eaten some food. + * @method foodEaten + * @return {bool} Whether a new food was able to spawn (true) + * or not (false) after the snake eats food. + */ + me.foodEaten = function () { + config.onLengthUpdate(mySnake.snakeLength); + elmLengthPanel.innerHTML = "Length: " + mySnake.snakeLength; + if (mySnake.snakeLength > localStorage[HIGH_SCORE_KEY]) { + localStorage.setItem(HIGH_SCORE_KEY, mySnake.snakeLength); + elmHighscorePanel.innerHTML = + "Highscore: " + localStorage[HIGH_SCORE_KEY]; } - if (evt.preventDefault) { - evt.preventDefault(); + if (!myFood.randomlyPlaceFood()) { + return false; } - return false; + return true; }; - // Search for #listenerX to see where this is removed - SNAKE.addEventListener(elmContainer, "keydown", myKeyListener, false); - SNAKE.addEventListener(elmContainer, "visibilitychange", myWindowListener, false); - }; + /** + * This method is called when the snake dies. + * @method handleDeath + */ + me.handleDeath = function () { + handleEndCondition(elmTryAgain); + config.onDeath({ startAIGame: me.startAIGame }); + }; - /** - * This method is called when the snake has eaten some food. - * @method foodEaten - * @return {bool} Whether a new food was able to spawn (true) - * or not (false) after the snake eats food. - */ - me.foodEaten = function () { - elmLengthPanel.innerHTML = "Length: " + mySnake.snakeLength; - if (mySnake.snakeLength > localStorage.jsSnakeHighScore) { - localStorage.setItem("jsSnakeHighScore", mySnake.snakeLength); - elmHighscorePanel.innerHTML = "Highscore: " + localStorage.jsSnakeHighScore; - } - if (!myFood.randomlyPlaceFood()) { - return false; - } - return true; - }; + /** + * This method is called when the snake wins. + * @method handleWin + */ + me.handleWin = function () { + handleEndCondition(elmWin); + config.onWin({ startAIGame: me.startAIGame }); + }; - /** - * This method is called when the snake dies. - * @method handleDeath - */ - me.handleDeath = function () { - handleEndCondition(elmTryAgain); - }; + me.setSpeed = (speed) => { + mySnake.setSpeed(speed); + }; + me.getSpeed = () => { + return mySnake.getSpeed(); + }; - /** - * This method is called when the snake wins. - * @method handleWin - */ - me.handleWin = function () { - handleEndCondition(elmWin); - }; + me.startAIGame = () => { + mySnake.rebirth(); + me.setBoardState(2); // start the game! + mySnake.go(); + }; - // --------------------------------------------------------------------- - // Initialize - // --------------------------------------------------------------------- + // --------------------------------------------------------------------- + // Initialize + // --------------------------------------------------------------------- + + config.fullScreen = + typeof config.fullScreen === "undefined" ? false : config.fullScreen; + config.top = typeof config.top === "undefined" ? 0 : config.top; + config.left = typeof config.left === "undefined" ? 0 : config.left; + config.width = typeof config.width === "undefined" ? 400 : config.width; + config.height = + typeof config.height === "undefined" ? 400 : config.height; + config.premoveOnPause = + typeof config.premoveOnPause === "undefined" + ? false + : config.premoveOnPause; - config.fullScreen = (typeof config.fullScreen === "undefined") ? false : config.fullScreen; - config.top = (typeof config.top === "undefined") ? 0 : config.top; - config.left = (typeof config.left === "undefined") ? 0 : config.left; - config.width = (typeof config.width === "undefined") ? 400 : config.width; - config.height = (typeof config.height === "undefined") ? 400 : config.height; - config.premoveOnPause = (typeof config.premoveOnPause === "undefined") ? false : config.premoveOnPause; + if (config.fullScreen) { + SNAKE.addEventListener( + window, + "resize", + function () { + me.setupPlayingField(); + }, + false, + ); + } - if (config.fullScreen) { - SNAKE.addEventListener(window, "resize", function () { - me.setupPlayingField(); - }, false); - } + me.setBoardState(BOARD_NOT_READY); - me.setBoardState(0); + if (config.boardContainer) { + me.setBoardContainer(config.boardContainer); + } - if (config.boardContainer) { - me.setBoardContainer(config.boardContainer); - } + const reloadGame = function () { + me.resetBoard(); + me.setBoardState(BOARD_READY); + me.getBoardContainer().focus(); + }; - }; // end return function -})(); + if (config.onInit) { + config.onInit({ + reloadGame, + getSpeed: me.getSpeed, + setSpeed: me.setSpeed, + startAIGame: me.startAIGame, + }); + } + }; // end return function + })(); From df3d88ec11da90aba952b4d26ee911597814d4e7 Mon Sep 17 00:00:00 2001 From: patorjk Date: Thu, 13 Feb 2025 21:49:59 -0500 Subject: [PATCH 12/17] updates --- README.md | 43 ++++++++++++++++++++++++++++ src/ai-example.html | 2 +- src/js/ai-init.js | 43 ++++++++++++++++++++++++++-- src/js/snake.js | 68 +++++++++++++++++++++++++++++---------------- 4 files changed, 128 insertions(+), 28 deletions(-) diff --git a/README.md b/README.md index 8577b786..641e7803 100755 --- a/README.md +++ b/README.md @@ -37,6 +37,49 @@ npx parcel src/index.html Runs on http://localhost:1234 +## AI Snake + +If you want to control the snake via an AI algorithm see the ai-init.js and ai-example files. + +Essentially all you have to do is run `params.startAIGame();` when initializing and pass in a `moveSnakeWithAI` method +which is run before the snake does each move. + +```js + moveSnakeWithAI: ({ + grid, + snakeHead, + currentDirection, + isFirstGameMove, + setDirection, + }) => { + + /* + Direction: + 0 + 3 1 + 2 + */ + + // This is NOT a real hamiltonian cycle. It misses some values, I'm just including this here as an example of + // a look-up type table that you could do. + const hamiltonianCycleGrid = [ + [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + [0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 0], + [0, 0, 2, 3, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 0], + [0, 0, 2, 0, 0, 3, 0, 2, 0, 2, 0, 2, 0, 2, 0], + [0, 0, 2, 0, 2, 2, 0, 2, 0, 2, 0, 2, 0, 2, 0], + [0, 0, 3, 0, 3, 3, 3, 3, 0, 3, 0, 3, 0, 3, 0], + [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + ]; + + const newDirection = hamiltonianCycleGrid[snakeHead.row][snakeHead.col]; + setDirection(newDirection); + }, + onInit: (params) => { + params.startAIGame(); // This start an AI game + }, +``` + ## Contributors Thanks goes to these people: ([emoji key](https://allcontributors.org/docs/en/emoji-key)) diff --git a/src/ai-example.html b/src/ai-example.html index e1acb6ad..d3ca29d7 100644 --- a/src/ai-example.html +++ b/src/ai-example.html @@ -124,7 +124,7 @@
- + From 2dd6f1b8d1c95f1d100bf038f75bfaa234723ee8 Mon Sep 17 00:00:00 2001 From: patorjk Date: Thu, 13 Feb 2025 22:16:49 -0500 Subject: [PATCH 16/17] game note --- README.md | 2 ++ src/index.html | 1 - 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 641e7803..b3a2f430 100755 --- a/README.md +++ b/README.md @@ -8,6 +8,8 @@ You can now play and edit the game live in codesandbox: https://codesandbox.io/s/github/patorjk/JavaScript-Snake?file=/index.html +**2025: Looks like CSS inside the sandbox isn't working properly, in the game it works fine though** + On first load sometimes the game frame will not load correctly and you'll need to press the refresh icon above its display panel to get the game to show. Original game is located here: diff --git a/src/index.html b/src/index.html index 291c88ce..03dc6b10 100755 --- a/src/index.html +++ b/src/index.html @@ -38,7 +38,6 @@ newCss.rel = "stylesheet"; newCss.type = "text/css"; newCss.href = themeUrl; - console.log(newCss.href); document.head.appendChild(newCss); } From 5702346689d4af03d7b5635005c34fa695d03802 Mon Sep 17 00:00:00 2001 From: patorjk Date: Thu, 13 Feb 2025 22:17:43 -0500 Subject: [PATCH 17/17] clean up --- README.md | 5 ----- 1 file changed, 5 deletions(-) diff --git a/README.md b/README.md index b3a2f430..0956f864 100755 --- a/README.md +++ b/README.md @@ -119,8 +119,3 @@ Thanks goes to these people: ([emoji key](https://allcontributors.org/docs/en/em - -TODO: - -- Add in what was added to Subpixel Snake --