From 2b04718f33003eaf8c4e0b4e288304b9cf34bb7d Mon Sep 17 00:00:00 2001 From: funman300 Date: Wed, 29 Apr 2026 01:27:31 +0000 Subject: [PATCH] =?UTF-8?q?feat(assetgen):=20upgrade=20card=20backs=20and?= =?UTF-8?q?=20backgrounds=20to=20120=C3=97168=20with=20richer=20patterns?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replace 16×16 placeholder PNGs with 120×168 canvas-drawn art matching card face dimensions. Each card back has a distinctive coloured pattern (blue diamond grid, red crosshatch, green circle array, purple concentric diamonds, teal horizontal stripes). Each background has textured detail (green felt weave, wood plank grain, navy star field, burgundy diagonal tile, charcoal checkerboard). Removes the now-unused save_small_png/make_small helpers. Co-Authored-By: Claude Sonnet 4.6 --- assets/backgrounds/bg_0.png | Bin 451 -> 32378 bytes assets/backgrounds/bg_1.png | Bin 218 -> 2000 bytes assets/backgrounds/bg_2.png | Bin 247 -> 4404 bytes assets/backgrounds/bg_3.png | Bin 559 -> 22620 bytes assets/backgrounds/bg_4.png | Bin 675 -> 25054 bytes assets/cards/backs/back_0.png | Bin 221 -> 23645 bytes assets/cards/backs/back_1.png | Bin 943 -> 34215 bytes assets/cards/backs/back_2.png | Bin 344 -> 9323 bytes assets/cards/backs/back_3.png | Bin 337 -> 20785 bytes assets/cards/backs/back_4.png | Bin 299 -> 4113 bytes solitaire_assetgen/src/bin/gen_art.rs | 351 ++++++++++++++++++++++---- 11 files changed, 298 insertions(+), 53 deletions(-) diff --git a/assets/backgrounds/bg_0.png b/assets/backgrounds/bg_0.png index 8848cb69997c8e1639363b38bfd4f2b162dbb57e..c75dc16f39489debf5620d69584832e292ebe83d 100644 GIT binary patch literal 32378 zcmeI5TS${(7{|X@SQ(>>E&_KEM1&L+IAYL&Qr2M|ETe)ft%!&mW0K9L(xfv&y9;AP zLkTPjw{GTPW$OSDB{>LN=xlXS8fzbg;;6A|&@Pnu$;Q~;=Yc$SE(V+Rm(lL4;8{aiHr0aQq zvbyK!;kBe1iwJyR z;IixdC1VxgCsbOrAFLO>>0LNTc0Xr)=p25Jxwi8StDXOUUpW_4#R>vml4nzC=O^DU ztQS4n5$L7Byz{5-s|}02lWLcR*tgQuCsh2RWWDI}Zg(9Mb(6+1 zI8_#S^31cEyxK|KSJoA0Bbp;&GI}ia2^BRZ>qQ^ARXxf}GyNDqMGNR}v0n7>$BA`O{+-X{F=&8_&VOf@cj*EE z005931OWh`gU?v^q5%N%jsFs*3jhEOO3YeCGo~&805tp&yj3(`>H+{j!x_X|Mf3G8 z0RRy3#G!N%U_^BI0RS>U{kc3UtZg)Wy-NT9M10V!Z8VI%O8@`>0000)6D`y24QV_i zRJ0Hk%{X=e0001xWnhSP=>h-%0FY&1h;``#0001xWnc&i05TzY)@F3ZDw?l%2><{9 zAj{Z2Ywr>O002Oiv3uU$B>(^b004kAdh29F{%m;z00000#j9FUI~_;>khv$0wTeap zfXKawtb5UnZ8S&#(6}CybuSvXm*)Edute+v34mPMno}jGV!H{Yi;&U<000000D%4F z=ePn$+}9WY0GZJNm;oSQtO4)vGG+kK7?%O>l9<~|kpMsf011GMqgF(5FaUsnsZXpI z9SML8nv^*V%kWmwxB`gAm^`RxF)A7f02>JjM7Kdvx`-%UTAJr-D>SMvc2jX;ro3d>Qm%KE9lQ7sjo7Nz literal 451 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4(FKVC?dAaSW+oe0zX-flB1GV;}#Q zzw145W_gi!^19sH+n^}3XWlfg_4AC3mEQd<+n!amtlc{Ms{gk9hxhqz?t6M{`<{=I zdl<_9y_w6u>!WUd4cmG7O|_?c^D7@4S1`W&bJJSBv zKR1`#y#Q;qsXy^e*L>g8-t!MwcYIENUvmMX_1}cI(RnqerRN{yE_iUPt$!46 zZ@=?nnz>!G_=9uv_kMPSX#MHDEq^E2cKri$?W>h3--$M{(2U!H?{7T$7%$Dk;CBW>gTe~DWM4f5OVRl diff --git a/assets/backgrounds/bg_1.png b/assets/backgrounds/bg_1.png index c5d24dd750f018f051b1b6b24f240d72b9d47c72..ef9525e973f4b75a33dec7827539b0def8672393 100644 GIT binary patch literal 2000 zcmeAS@N?(olHy`uVBq!ia0vp^6+pa#gAGV(M``_KU|^r_>Eakt!T9z7^8%H~X~#bP zFMrp2;>_|Q@8os4x3@u2X3xB7UhC%>87sZ}S++f^YFWE=_ErD>eTj!-zSfIYec_dU zw(9@t3)%aR@WL5vH}1_SzWQJGx4SmOms|RU%{yQH*Ft45ZZm%dG~oEZi(CwQzj@zD zSodo`7b>ISZLekc-}@Wuw=g-Z|0`rZWA(rFPACkCgzDsTq5sR@$ggEUbpc(SG8!02 y@iH11qk(}v$Bw3q(UdWoGJsVb-iqy!JmVa`33=z1PZR{!)C``kelF{r5}E+Lm3M>y delta 169 zcmcb>e~VGIGr-TCmrII^fq{Y7)59eQNDF{42OE%-|NK7@NG+VGYE`|>|8stO+;7!9 zga2hGzGePQ8Q+}KLFMF{y z{t+8cXU=?}(!Jlj?o?W}t1FSqmyn}2S9EYG+|LFJ@y T$kN9^YZ*LU{an^LB{Ts5S65DZ diff --git a/assets/backgrounds/bg_2.png b/assets/backgrounds/bg_2.png index 8501a49283bed9b4b1a250d86631f168dae3b5a8..2023a48002c74508c16a7a1abce98b0f4d8a5560 100644 GIT binary patch literal 4404 zcmcgwZAep57`{`~FoylfK|+HP1SJLq`6E9{6w|;}C?kt4h@!F~7}TcjgQ6lVghcxh zOfyPxg?S& z@4D)aoavQX^r6>+&WNW7FxO_pHD5Swtp$`jr`~dXvdd+ zi}s6rk{f!V>Dhoiko{cYX?9;Gdc+4{WMuKP7R~0BP5vs2O1mhS6J~n6U-U7qjHY21hcCdvF45C9bqCDXgQuf|>m37M@va_-d&$!ShfbQCM(=04Knq z#g#hO&Dv3)|CdO0k9;Jd1N>64x|T3HZHd$0^4*j5t+|aS;S$wTk^EJ^4Q%b6^yr<0 z7;Z)hqpKq%DTxz$tzTEfEQOy-6Z05|6Jt;)rVkX76;~^iv3i z0CuiYlc&X712xK@+v$93`h?4_zlJEvBXqbO zOM%vJok1L%Wt$*X5J#0^&YM^bfgpXFrXe$Pb!gvte2S3)8LU3Zge= zEb?Z+Sgx&Mt`6;6UJzD3Y%4{IZSPCRU;~lR2s%Nwt1RmHF}BsQv-cmGB7Z9ztwA(y z^Y~;Dyp9-od<}P)P4J)!R%e;mL8qUBYTpsY9>kED%}(i1*^RI}VRJ0n*!wUj@+28D zBt;l|!dRd^J4K#EH-o*+Z;HG*l=+p?O)wsdHXeBk$Re1G_TlS}Jz>^7N^^D+kSbvQ f4?=vrd3R4Fzf3qcKH>=e8-kUUR226Xoxb)DUdQ?Q delta 199 zcmdm@^qo<)Gr-TCmrII^fq{Y7)59eQNDF{42OE%-|NK7@NbQ@bYE{2&Z}GFx3de8f z{s~&A$F+(xe>CWo8HbfUVn&tQ~9_48e+ohT&79_js4;N?YQE^VCKaK QfsSJEboFyt=akR{03uFeG5`Po diff --git a/assets/backgrounds/bg_3.png b/assets/backgrounds/bg_3.png index c61c2994b3e88c93cdcfca8761ad6d80d859a5d4..7302d3c613b6627e10d3240110d3cb58a85c6d12 100644 GIT binary patch literal 22620 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 literal 559 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4(FKVEpFk;uuoF`1Szv0+q;V$3Ffq zf7g5B%<>}d6&%9|~>*pC6E4}+!wmqwAS-W-iRsU`Im8a(#pMSvmUDf^e^0S{vDv@+uh|ZaBcK&Jl_j7hHbj#1# zG>bogvzZ-02HG4r|88#Wh3I#4D%tdr*x?Jd->}P__Y$rgS!;7T*fE%H0lUja{fpS` x<$pIccu)5S?F%J>##wr`N2^P{N53S)L`;f##jVrN!9KtlZ zDM83w`Z$>fS-Z$Clon($mmu6ISTQ`f#^ACU>yE9fFd#Mj55vp`f7p-9dl=rC=fA(_ z|2*%rLzkM*RaYIX5<*l*&WBq{-%9EIa_^qf=keBKMIo*|i-a34E1qmhQjc62ozpk( ztv-4`|DwC8eWEj+*m>O;86UmyYWzff?dtEl(>G(!ADq7R`J&&*_^2r85tZ#r?6W7P;sj__gT7qXnsDQ3{^!+&q)1$w{php`{u77yq{o=lan_DJgdQJS)ny3H? zH@A$Thy9FE%Rw9p5u-3DBSwK7%g{qZj~E4|XT&Hlmn24^c{MSL7-eg&L5wnU6iaW5 z7)6W%`3PJ_El0JSZWLt66QhVx_EwIV5~Es9H;QhQt>sdN9vXUdqv%FKd_*@26ftUh zFdXMbfy47SHwqji$hlGAu*J#@Jr?y?)MHVPMZNMUS&rZQueF@LQIKiH7IW0JVo{Gp zJzFzpp42ld=9YzZwwSZU9CUcWWz=#|%Z+_44+oXt;n#`M|2Bxo+2-&>W81(V@|bU5 literal 675 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4(FKV9N4zaSW+oe0zX-flB1GV;}#Q zzw145W_gi!^19sH+n^}3XWlfg_4AC3mEQd<+n!amtlc{Ms{b~B`yU7UElwBj{CZ7& ze&vT|`NC<>i(aqwxBL8n-TskI_yTs@7Z0D!%-j3*WV+m+2kvv8?z~g=dh&T2ByAJl zUgod+pnUFA3=UPjzAR{;oxTgZ me<9l3MuP=489+l*p7A#4;f0@fJ`V&YJ_b)$KbLh*2~7Z}mu}$z diff --git a/assets/cards/backs/back_0.png b/assets/cards/backs/back_0.png index e49bed3eaa543c939021f4c71874ac00aa1272f9..b673bf0dcd26b0f7ec12220eaa38658f8ba3538b 100644 GIT binary patch literal 23645 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 aYio;ty0`esHYxgN*^-ruk39G0_WuFiFim6t literal 943 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4(FKU@r4?aSW+oe0zX-flB1GV;}#Q zzw145W_gi!^19sH+n^}3XWlfg_4AC3mEQd<+n!amtlc{Ms{b~5-VdVY_kL6~^zZ(B z?l?ou(Oz>qxd)Hm?fGoT5MTJXx1asT4(sR6KsnnDYA~7E!x*=d9(KaT@gN zlXRZJf#Y{8pC>cydvr`%p8rE(`MsYK4eNJ&Ja(M9=FZ%5JGKYfd3!#7WRNd^KDVFo z!u0zE&Gz_B#p1lw-xslnGU9Ze!#4T9r1&0e&|>}l581Fe`bU>^evJ(le=^kmOx@4_Ek2!vDs%-g~%G zK4aal{akww2isqW`C2bp)xNxL!OmCzwZ8EA|8@Axu>X&${rS-U)q6jx@3rJ_0BewY zFn#}%=R053uQ&g<#QZtq1#6qH%x9VZe475pCj9UFugB(pd1k`^HmR~9{@al-Su^a=~ zO*RMg>rb99zWP5d|Bq+>IpziB6|dN5vHy6g|Fd%4uluii?O&d)WFY9+%D}xpcJGn- z{`~mc>VP0kL&9HJJ%oFf317} z>C=V#_y1qG|3UogqxYXa-Esf^{|oUS)_;BU{!`JN_wVap=rdGcxc2j+ijU=$mh*0d z6)&oyCI>TY<3E8Mvqu5q<|iO$Ryaa@a}wl%k4=BT{+tB%8tYGR2&jTR&Hd@S{TJ~+ z-r(R6e**H(kLi0r0i}P!cYDlvl+gZ1SP$60`jsI6#!Y|(8$rk2DLMTWHL=jkLvbSD zKqv;MiMSAIaxfG7o)uI~b3d+w)6~1~py*@RGqkfN_HyKZAQi)_A`ml-e)fL=L%=_RngBqC;oUsmJ@x*s5oRIjEWU{;6W|#A0x%My29^5oVE3aRr4v7tpgdg_eM1SA-~q(w}Uk`j!Dpai{@K zRnNbHN-${ING%RVarhHfr;(j%|6{8>i!SS4M{T>*Q&QpLcAWX$B3qQE7u`H0eiYn- zxC3rZh+m~92eav@zl!9>7w$BN(#B)JED=a(I}Uu-#O~PoDO3!vI1$V+`lk#oHP62V zH4G~tEokyNz?LOu&Kwr?SN(d@n%1~;I=Btb{TZ_)5RyGNre3n>8!^$3Y9l#n}~Obu9y!!B^D+6nHZLd!-faj<0d;numMTW{6%BQ?7b zDE$!3v5oFmI7T7JNOLHI9gGJsO9a}C#Ly^fVs-3i`KMG2FY%+8VMK?n3+?+~bf~}R z&=sbAf8PESs1l}9@vq;7S>)5RyNA6^N%2T8qyU2qjZ#`Dp^U&XJit;MJ_3(+=7F0{ zkg~CYN*v6rKI}So^zu+;AT_%YsQnNuWA8{qqbQ>gC_O^t#urLOh?3?|M*SH+U^dGK zd|rd%+Vqb*c(@)iluU7Wxqie9BieUehDZHHhpsT~`}6(a`5r12|J{!;i+qYJr~%Ki zqf?PsM^i_qBK41tPDKvJVWZKhNaS?^;K9q$sYs$`Ea^NIiMf6UI4v0pSzNQ~|LPy^ Z_Vf2xzF2Es16)MJ;OXk;vd$@?2>@#`ek=e0 literal 344 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4(FKV3hZCaSW+oe0zX-flB1GV;}#Q zzw145W_gi!^19sH+n^}3XWlfg_4AC3mEQd<+n!amtlc{Ms{gjVpB>GM_V3N#Ie9Ms zu8F_j)}EgGrshKLo&5LF?^2#O=RKKu;T!wCgnw^QsR_C7QB>7c-!D?PmM>BMe*5<{ z>zh9pNLQ+D`P*ndquv^oO1X`qYUllX+wYt_$A0(3-*5Y#`jy$eaGS@OTmOLf*?m4# z>gG2TRqwWc*Dc?K;`nr@+wv97Kes!hP>zopr03~a* A5&!@I diff --git a/assets/cards/backs/back_3.png b/assets/cards/backs/back_3.png index 0532928239de1f3f928721fb4805385a3f78ae62..ac070a0805acea33ad18634157349bae1debb5bb 100644 GIT binary patch literal 20785 zcmeHPYitx%6rQ%$k~XB8NSdG)6$qsKSk$O7Y$y=0RuT$YY(&$A$R9;TA(355x1~uV zf>4C;NQ^Cl5rjY!BSMpHw>Cfvq6HIdl!k>q5z}s8u-op-&b?cDX7AkHId=%NKbr7J z3Nv$O&OPUR=R4oIUoKykGdXo?sw7F1b6;Ql=IGzn(ci}=Jv#d5oK;x?Nm}mBUA!>g zn$T09bZEvq`!Do|Hudgox_orQ()Uk&eEpa3uMfVe-2X;(W|ge=9ugD*{d!k9kTdle3Rn+!|h#Ecu;;?;!XNEhx|B+ zK99V#MBn-e`K=$Rr>|`tf4}qcYbW%{@9mf^zu=@&`iA}T8%pFAP20f}7T)j#=I={c zAbxc$wef_7!KP zm&#i&^X5Efdz#Iz<>Rg3nMcEi=UrQQ-B;&2Iw0L{nSZe>p>A+q-R|yt9OLosQ3$rj zr%qsPEf@41Ci{sRCuOtC8?=Ucc{>9N**IBdM0L&LPaE zfUehpaZV5+?2MoGdUP12uZ*{IfaMg1$NQ}@(Z2xcE;dA|X9_095N^`sAFYT`Pjszr#ykOCFm<;MXqa5ed=Lp6=azt~gjQLi zwpCw?fcI+2d#c{WtU&dDfx46v2STgx7n-}iHZ_KeNUMKuFfm5a2fd8e(zL7$o)+6q z*2~i^yT)or@2o(wmV%XyDgJj!b&bMaOwf$|g@K8^9#zVKV;a+T#>k3Vn)g{@Io9VU z7)vDu@vaWeWN=n+Cf3ukFJU9`8YUz9mts&w$AL>Lw)lYh^V7An`HgsUa|rkgdGPsa}RU1?iZCn~^|h zQoWvCPuIbvR@qFY;8h~m(xhi8G>{1_rO`alX@w-Jyb2MU{Dr@;!q)Lyf0(h%41MpE z(Cjt+#3d)i0BPo6(}DIdWp57Vmi!8M@fgN~fg$w*Q&q( z(v)FZcCp=za`gg)Xe$GP&1W#M7NkweJ_xK~0R#UtZ|nQ6ntO_D?2LB`f?_><^C8>= z!K2*x?!}1FxMKkxUyW1b13Mw4nL6H|23;G#SE`51a3=(3Ok=wsGWk*_Rt5%7;$uAr z4j`hnzX)sOl8Y?mLVA-Lv8J~I)7+06^20$efI@M>Mn^?iK#?V@xZu@xiYieB3mD9Y z;6tMzZ(z=55?*DMSY1FZr03f1dkny@!FmjA$hW%nr0%T~aAZ{41(XmIa3n(P#)Bic zB&t#B2GA{J-6K2Z#)A-}o*w2;C@8DFDHo`XlwOYY*7bPr4G z&ix*+3#F)3boR3ite7iG{IEFeHhp(4Es1~6P0jg~5e$KNpV@-kB}QO-rL^>fpJU*mem17U*E2$3pjNRl`(G2{ zyD9*=g$!<@uih3f5>Kcs35fes$sWcaF`%Rva> zO|c$g!yr2&O*b2+t|sTMwAtwgh<=(2ds`J*jNwPcJlu&egC_6caVSuGqDYCbunQGp zt5XZxY*Lp*!paGZyy+PuFrW)EA;%ayOviXR23BKTRj*n28y^O2LSkZGF9-J_?Q1AqYUXSMUh!jV1sKB5&>4<2o z7W_G67+7oj9d<&Fhfa_~0au0!zLSsZI}xm26h5=?e0E|_`s%e^8xQUpJql6EU9xQP JsYR>H{s*`#U6}v? literal 337 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4(FKV3hE5aSW+oe0zX-flB1GV;}#Q zzw145W_gi!^19sH+n^}3XWlfg_4AC3mEQd<+n!amtlc{Ms{i|5Si};Ls>o0oC_aE3JU|;bqxbnJj{0Z&`u!Q&n_VaaG->X4FpBuqK z&mV(?&cBU4U!!=Qb?@ny`UdBpf`s%>?4I}2Nsa+5#Q&i=-F|BQNs!PyPF$+aALpO< zH)P&zuqtk_%iEakt!T9z7^8%H~X~#bP zFMrp2;>_|Q@8os4x3@u2X3xB7UhC%>87sZ}S++f^YFWE=_ErD&|Fie!ulu#1Ywy4H zfA{Tt^pE`wnipUFZ}-|d?>UK*tN(qkT3TKqF2?|NR%L_z z&yDhrR{h@__fqy=E4u@dgDL{|9Le6#7ykG9&)xU`>Bfny|HAkF5c7iT|F_;Z=l`H? z|IIn(>;CK7dk^pa!0_U0{oC(nng5*Z|0@vw_x)F|_aF3Z7^?op|E~SaQ2!~}{z&Nm z>b;k&_i*z!#Qncsci-l~{69DN3$Olv-5y~S9`7e&N)mw@k)~5ppT0xI@JeD&IoKWK`cY{8U#pm} z@z3Aa{oW3Yc#0y5gy6;=|7Y@c%>+6$@_wN;X5zprNlJq3exw@ryL88^{parg{gw}m zcp~!!_J|@SxUpup8Fx#Jfg!hf-{UgOG>2D`6bFeP_1^RCb-~s8x%+>=z5mGdBMmYt z3Gr{Z`(+w1*cqOr?9PIJ0-!;AB?e&MN{#(_5zrFux_an?g6MMeE8d0PK zH&$bl$}XP;I`sUnzT1@;X%4R>_JSI_gW^Q=Ki*n@IP`z%zjxc~yTy-U7MdhP6e+=t z-PkwFX77AeKmV)j_RpAU4zDB$H3zV~ezY~def7WBf9~f07t`;;EHo+3sMv!WyRoAc zHG1PLEO|2F+_JSH~af`Pu#w$rm%`sY0k5<&co-w|zFZOZ~ ht)WJs+x= 1.0 - (thickness / rx.min(ry)) { + self.set(x, y, c); + } + } + } + } + fn set(&mut self, x: i32, y: i32, c: [u8; 4]) { if x < 0 || y < 0 || x >= W as i32 || y >= H as i32 { return; } let i = (y as u32 * W + x as u32) as usize * 4; @@ -352,67 +387,277 @@ fn save_png_wh(path: &Path, data: &[u8], w: u32, h: u32) { .unwrap_or_else(|e| panic!("png data error for {}: {e}", path.display())); } -fn save_small_png(path: &Path, pixels: &[u8; 1024]) { - save_png_wh(path, pixels, 16, 16); +// --------------------------------------------------------------------------- +// Card backs (120×168 with distinctive patterns) +// --------------------------------------------------------------------------- + +/// back_0 – blue: repeating diamond grid pattern +fn make_back_0() -> Canvas { + const BASE: [u8; 4] = [0x26, 0x4D, 0x8C, 0xFF]; + const LIGHT: [u8; 4] = [0x5A, 0x80, 0xBF, 0xFF]; + const HIGHLIGHT: [u8; 4] = [0xA0, 0xC0, 0xFF, 0xB0]; + let mut cv = Canvas::new(); + cv.fill_solid(BASE); + + // 2-pixel border + let bw = 4i32; + for x in 0..W as i32 { for t in 0..bw { cv.set(x, t, LIGHT); cv.set(x, H as i32 - 1 - t, LIGHT); } } + for y in 0..H as i32 { for t in 0..bw { cv.set(t, y, LIGHT); cv.set(W as i32 - 1 - t, y, LIGHT); } } + + // Diamond grid: row/col spacing + let gx = 18.0f32; + let gy = 18.0f32; + let rx = gx * 0.45; + let ry = gy * 0.45; + let mut row = 0; + let mut cy = 6.0f32 + gy * 0.5; + while cy < H as f32 - 4.0 { + let offset = if row % 2 == 0 { 0.0 } else { gx * 0.5 }; + let mut cx = 6.0f32 + gx * 0.5 + offset; + while cx < W as f32 - 4.0 { + cv.diamond_ring(cx, cy, rx, ry, 1.5, LIGHT); + // tiny highlight dot at centre of each diamond + cv.circle(cx, cy, 1.5, HIGHLIGHT); + cx += gx; + } + cy += gy; + row += 1; + } + cv } -fn make_small [u8; 4]>(f: F) -> [u8; 1024] { - let mut out = [0u8; 1024]; - for y in 0u32..16 { - for x in 0u32..16 { - let c = f(x, y); - let i = ((y * 16 + x) * 4) as usize; - out[i..i + 4].copy_from_slice(&c); +/// back_1 – red: diagonal crosshatch +fn make_back_1() -> Canvas { + const BASE: [u8; 4] = [0x8C, 0x1A, 0x1A, 0xFF]; + const LINE: [u8; 4] = [0xCC, 0x55, 0x55, 0xC0]; + const BORDER: [u8; 4] = [0xDD, 0x88, 0x88, 0xFF]; + let mut cv = Canvas::new(); + cv.fill_solid(BASE); + + // Diagonal lines every 12 px (NW→SE) + let spacing = 12i32; + for k in (-(H as i32)..W as i32).step_by(spacing as usize) { + for t in 0..W as i32 { + let y = t + k; + cv.set(t, y, LINE); + // 1 px thick — also set neighbour for slightly bolder line + cv.set(t, y + 1, LINE); } } - out + // Diagonal lines (NE→SW) + for k in (0..(W as i32 + H as i32)).step_by(spacing as usize) { + for t in 0..W as i32 { + let y = k - t; + cv.set(t, y, LINE); + cv.set(t, y + 1, LINE); + } + } + + // 4-pixel border + let bw = 4i32; + for x in 0..W as i32 { for t in 0..bw { cv.set(x, t, BORDER); cv.set(x, H as i32 - 1 - t, BORDER); } } + for y in 0..H as i32 { for t in 0..bw { cv.set(t, y, BORDER); cv.set(W as i32 - 1 - t, y, BORDER); } } + cv +} + +/// back_2 – green: evenly spaced small circle array +fn make_back_2() -> Canvas { + const BASE: [u8; 4] = [0x0D, 0x66, 0x1A, 0xFF]; + const DOT: [u8; 4] = [0x40, 0xCC, 0x55, 0xE0]; + const BORDER: [u8; 4] = [0x55, 0xDD, 0x66, 0xFF]; + let mut cv = Canvas::new(); + cv.fill_solid(BASE); + + // 4-pixel border + let bw = 4i32; + for x in 0..W as i32 { for t in 0..bw { cv.set(x, t, BORDER); cv.set(x, H as i32 - 1 - t, BORDER); } } + for y in 0..H as i32 { for t in 0..bw { cv.set(t, y, BORDER); cv.set(W as i32 - 1 - t, y, BORDER); } } + + // Circle array (staggered rows) + let gx = 16.0f32; + let gy = 16.0f32; + let r = 3.5f32; + let mut row = 0; + let mut cy = 8.0f32 + gy * 0.5; + while cy < H as f32 - 6.0 { + let offset = if row % 2 == 0 { 0.0 } else { gx * 0.5 }; + let mut cx = 8.0f32 + gx * 0.5 + offset; + while cx < W as f32 - 6.0 { + cv.circle(cx, cy, r, DOT); + cx += gx; + } + cy += gy; + row += 1; + } + cv +} + +/// back_3 – purple: concentric diamond outlines +fn make_back_3() -> Canvas { + const BASE: [u8; 4] = [0x59, 0x14, 0x85, 0xFF]; + const RING: [u8; 4] = [0xA0, 0x60, 0xDD, 0xD0]; + const BORDER: [u8; 4] = [0xBB, 0x77, 0xFF, 0xFF]; + let mut cv = Canvas::new(); + cv.fill_solid(BASE); + + // Concentric diamonds from centre + let cx = W as f32 * 0.5; + let cy = H as f32 * 0.5; + let mut rx = 8.0f32; + let step = 12.0f32; + while rx < (W as f32).max(H as f32) { + let ry = rx * (H as f32 / W as f32); + cv.diamond_ring(cx, cy, rx, ry, 1.5, RING); + rx += step; + } + + // 4-pixel border + let bw = 4i32; + for x in 0..W as i32 { for t in 0..bw { cv.set(x, t, BORDER); cv.set(x, H as i32 - 1 - t, BORDER); } } + for y in 0..H as i32 { for t in 0..bw { cv.set(t, y, BORDER); cv.set(W as i32 - 1 - t, y, BORDER); } } + cv +} + +/// back_4 – teal: horizontal stripes with thin decorative lines +fn make_back_4() -> Canvas { + const BASE: [u8; 4] = [0x0D, 0x66, 0x6B, 0xFF]; + const STRIPE: [u8; 4] = [0x1A, 0x99, 0xA0, 0x90]; + const DECO: [u8; 4] = [0x55, 0xCC, 0xD4, 0xA0]; + const BORDER: [u8; 4] = [0x44, 0xBB, 0xC4, 0xFF]; + let mut cv = Canvas::new(); + cv.fill_solid(BASE); + + // Horizontal stripes every 10 px (2 px wide) + let mut y = 6i32; + while y < H as i32 - 4 { + cv.hline(y, 5, W as i32 - 6, STRIPE); + cv.hline(y + 1, 5, W as i32 - 6, STRIPE); + y += 10; + } + // Thin decorative horizontal lines between stripes + let mut y = 10i32; + while y < H as i32 - 4 { + cv.hline(y, 14, W as i32 - 15, DECO); + y += 10; + } + + // 4-pixel border + let bw = 4i32; + for x in 0..W as i32 { for t in 0..bw { cv.set(x, t, BORDER); cv.set(x, H as i32 - 1 - t, BORDER); } } + for y in 0..H as i32 { for t in 0..bw { cv.set(t, y, BORDER); cv.set(W as i32 - 1 - t, y, BORDER); } } + cv } // --------------------------------------------------------------------------- -// Card backs (16×16 placeholder patterns) +// Backgrounds (120×168 textured patterns) // --------------------------------------------------------------------------- -fn make_back_0() -> [u8; 1024] { - make_small(|_, y| if y % 4 < 2 { [0xFF, 0xFF, 0xFF, 40] } else { [0x26, 0x4D, 0x8C, 0xFF] }) -} -fn make_back_1() -> [u8; 1024] { - make_small(|x, y| if (x + y) % 4 < 2 { [0xFF, 0xFF, 0xFF, 40] } else { [0x8C, 0x1A, 0x1A, 0xFF] }) -} -fn make_back_2() -> [u8; 1024] { - make_small(|x, y| if x.is_multiple_of(4) && y.is_multiple_of(4) { [0xFF, 0xFF, 0xFF, 0xFF] } else { [0x0D, 0x66, 0x1A, 0xFF] }) -} -fn make_back_3() -> [u8; 1024] { - make_small(|x, y| { - let dx = (x as i32 - 8).unsigned_abs(); - let dy = (y as i32 - 8).unsigned_abs(); - if dx + dy <= 4 { [0xFF, 0xFF, 0xFF, 0xFF] } else { [0x59, 0x14, 0x85, 0xFF] } - }) -} -fn make_back_4() -> [u8; 1024] { - make_small(|x, y| if x == 0 || x == 15 || y == 0 || y == 15 { [0xFF, 0xFF, 0xFF, 0xFF] } else { [0x0D, 0x66, 0x6B, 0xFF] }) +/// bg_0 – dark green felt: subtle grid of faint lines giving a woven texture +fn make_bg_0() -> Canvas { + const BASE: [u8; 4] = [0x1A, 0x4D, 0x1A, 0xFF]; + const WARP: [u8; 4] = [0x22, 0x60, 0x22, 0x90]; // slightly lighter horizontal threads + const WEFT: [u8; 4] = [0x15, 0x40, 0x15, 0x90]; // slightly darker vertical threads + let mut cv = Canvas::new(); + cv.fill_solid(BASE); + // Horizontal warp lines every 4 px + for y in (0..H as i32).step_by(4) { + cv.hline(y, 0, W as i32 - 1, WARP); + } + // Vertical weft lines every 4 px + for x in (0..W as i32).step_by(4) { + cv.vline(x, 0, H as i32 - 1, WEFT); + } + cv } -// --------------------------------------------------------------------------- -// Backgrounds (16×16 placeholder patterns) -// --------------------------------------------------------------------------- +/// bg_1 – wood brown: horizontal planks with grain lines +fn make_bg_1() -> Canvas { + const BASE: [u8; 4] = [0x40, 0x2D, 0x1A, 0xFF]; + const PLANK_EDGE: [u8; 4] = [0x28, 0x1A, 0x0A, 0xFF]; // dark plank separator + const GRAIN: [u8; 4] = [0x55, 0x3D, 0x28, 0xA0]; // lighter grain streak + let mut cv = Canvas::new(); + cv.fill_solid(BASE); + // Horizontal plank edges every 24 px + for y in (0..H as i32).step_by(24) { + cv.hline(y, 0, W as i32 - 1, PLANK_EDGE); + cv.hline(y + 1, 0, W as i32 - 1, PLANK_EDGE); + } + // Grain lines within each plank (every 3 px between plank edges) + for y in (0..H as i32).step_by(3) { + // Skip the plank edge rows + if y % 24 < 2 { continue; } + cv.hline(y, 2, W as i32 - 3, GRAIN); + } + cv +} -fn make_bg_0() -> [u8; 1024] { - make_small(|x, y| if x.is_multiple_of(8) || y.is_multiple_of(8) { [0xFF, 0xFF, 0xFF, 30] } else { [0x1A, 0x4D, 0x1A, 0xFF] }) +/// bg_2 – navy: star-field dots scattered in a regular grid +fn make_bg_2() -> Canvas { + const BASE: [u8; 4] = [0x0D, 0x14, 0x38, 0xFF]; + const STAR_A: [u8; 4] = [0xCC, 0xDD, 0xFF, 0xD0]; + const STAR_B: [u8; 4] = [0x80, 0xA0, 0xDD, 0x80]; + let mut cv = Canvas::new(); + cv.fill_solid(BASE); + // Bright small stars on a staggered grid + let gx = 14.0f32; + let gy = 16.0f32; + let mut row = 0u32; + let mut cy = gy * 0.5; + while cy < H as f32 { + let offset = if row.is_multiple_of(2) { 0.0 } else { gx * 0.5 }; + let mut cx = gx * 0.5 + offset; + while cx < W as f32 { + // alternate bright/dim to give depth + let c = if (row + (cx / gx) as u32).is_multiple_of(3) { STAR_A } else { STAR_B }; + cv.circle(cx, cy, 1.0, c); + cx += gx; + } + cy += gy; + row += 1; + } + cv } -fn make_bg_1() -> [u8; 1024] { - make_small(|_, y| if y.is_multiple_of(2) { [0xFF, 0xFF, 0xFF, 20] } else { [0x40, 0x2D, 0x1A, 0xFF] }) + +/// bg_3 – burgundy: diagonal tile pattern +fn make_bg_3() -> Canvas { + const BASE: [u8; 4] = [0x4D, 0x0D, 0x14, 0xFF]; + const LINE: [u8; 4] = [0x77, 0x22, 0x30, 0xB0]; + const ACCENT: [u8; 4] = [0x99, 0x33, 0x44, 0x80]; + let mut cv = Canvas::new(); + cv.fill_solid(BASE); + // Diagonal lines in one direction every 16 px + let spacing = 16i32; + for k in (-(H as i32)..W as i32 + H as i32).step_by(spacing as usize) { + for t in 0..W as i32 { + let y = t + k; + cv.set(t, y, LINE); + } + } + // Diagonal lines in the other direction every 16 px (accent colour) + for k in (0..W as i32 + H as i32).step_by(spacing as usize) { + for t in 0..W as i32 { + let y = k - t; + cv.set(t, y, ACCENT); + } + } + cv } -fn make_bg_2() -> [u8; 1024] { - make_small(|x, y| { - let off: u32 = if (y / 4).is_multiple_of(2) { 0 } else { 4 }; - if (x + off).is_multiple_of(8) && y.is_multiple_of(8) { [0xFF, 0xFF, 0xFF, 0xFF] } else { [0x0D, 0x14, 0x38, 0xFF] } - }) -} -fn make_bg_3() -> [u8; 1024] { - make_small(|x, y| if (x + y).is_multiple_of(8) { [0xFF, 0xFF, 0xFF, 30] } else { [0x4D, 0x0D, 0x14, 0xFF] }) -} -fn make_bg_4() -> [u8; 1024] { - make_small(|x, y| if (x + y).is_multiple_of(2) && x.is_multiple_of(3) { [0xFF, 0xFF, 0xFF, 20] } else { [0x1F, 0x1F, 0x24, 0xFF] }) + +/// bg_4 – charcoal: subtle checkerboard texture +fn make_bg_4() -> Canvas { + const DARK: [u8; 4] = [0x1F, 0x1F, 0x24, 0xFF]; + const LIGHT: [u8; 4] = [0x2C, 0x2C, 0x33, 0xFF]; + let mut cv = Canvas::new(); + cv.fill_solid(DARK); + // 4×4 checkerboard + for y in 0..H as i32 { + for x in 0..W as i32 { + if ((x / 4) + (y / 4)) % 2 == 0 { + cv.set(x, y, LIGHT); + } + } + } + cv } // --------------------------------------------------------------------------- @@ -451,16 +696,16 @@ fn main() { } // Card backs - for (i, pixels) in [make_back_0(), make_back_1(), make_back_2(), make_back_3(), make_back_4()].iter().enumerate() { + for (i, cv) in [make_back_0(), make_back_1(), make_back_2(), make_back_3(), make_back_4()].iter().enumerate() { let path = root.join(format!("assets/cards/backs/back_{i}.png")); - save_small_png(&path, pixels); + save_card_png(&path, cv); println!("wrote {}", path.display()); } // Backgrounds - for (i, pixels) in [make_bg_0(), make_bg_1(), make_bg_2(), make_bg_3(), make_bg_4()].iter().enumerate() { + for (i, cv) in [make_bg_0(), make_bg_1(), make_bg_2(), make_bg_3(), make_bg_4()].iter().enumerate() { let path = root.join(format!("assets/backgrounds/bg_{i}.png")); - save_small_png(&path, pixels); + save_card_png(&path, cv); println!("wrote {}", path.display()); }