From a81ec7901d5dde5d54e1b40c8feadbf9df946d3c Mon Sep 17 00:00:00 2001 From: rail Date: Sat, 22 Nov 2025 22:47:22 +0300 Subject: [PATCH] Implement multi-layer fluid simulation with organic particle flow Replace chaotic particle motion with smooth fluid dynamics: - Three-layer flow field system for complex organic motion - Large sweeping currents (0.003 scale) - Medium turbulence (0.006 scale) - Fine detail waves (0.001 scale) - Smooth acceleration and velocity damping (0.95) - Speed limiting (max 2px/frame) for graceful movement - Particles start at rest and flow along force fields - Visual improvements: - Radial gradient glows with green halos - Semi-transparent trail effects (0.12 alpha) - 1200 particles with 500-1000 frame lifespans - Soft green color scheme (rgba 100,255,180) - Canvas positioned behind content (z-index: 0) - Added CanvasGradient feature to web-sys Result: Beautiful rain-drop style fluid animation --- Cargo.toml | 2 +- dist/railwayka_landing.d.ts | 4 +- dist/railwayka_landing.js | 22 +++-- dist/railwayka_landing_bg.wasm | Bin 61818 -> 65291 bytes dist/railwayka_landing_bg.wasm.d.ts | 4 +- src/lib.rs | 142 ++++++++++++++++++++-------- 6 files changed, 126 insertions(+), 48 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 5941ba7..c4c19ae 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -29,7 +29,7 @@ features = [ "DomTokenList", "HtmlCanvasElement", "CanvasRenderingContext2d", - "Performance", + "CanvasGradient", ] [profile.release] diff --git a/dist/railwayka_landing.d.ts b/dist/railwayka_landing.d.ts index f9fa8af..0bda2d8 100644 --- a/dist/railwayka_landing.d.ts +++ b/dist/railwayka_landing.d.ts @@ -11,8 +11,8 @@ export interface InitOutput { readonly __wbindgen_export_1: (a: number, b: number) => number; readonly __wbindgen_export_2: (a: number, b: number, c: number, d: number) => number; readonly __wbindgen_export_3: WebAssembly.Table; - readonly __wbindgen_export_4: (a: number, b: number, c: number, d: number) => void; - readonly __wbindgen_export_5: (a: number, b: number) => void; + readonly __wbindgen_export_4: (a: number, b: number) => void; + readonly __wbindgen_export_5: (a: number, b: number, c: number, d: number) => void; readonly __wbindgen_start: () => void; } diff --git a/dist/railwayka_landing.js b/dist/railwayka_landing.js index 2b765ae..2e16c44 100644 --- a/dist/railwayka_landing.js +++ b/dist/railwayka_landing.js @@ -237,12 +237,12 @@ export function main() { wasm.main(); } -function __wbg_adapter_4(arg0, arg1, arg2, arg3) { - wasm.__wbindgen_export_4(arg0, arg1, addHeapObject(arg2), addHeapObject(arg3)); +function __wbg_adapter_4(arg0, arg1) { + wasm.__wbindgen_export_4(arg0, arg1); } -function __wbg_adapter_9(arg0, arg1) { - wasm.__wbindgen_export_5(arg0, arg1); +function __wbg_adapter_7(arg0, arg1, arg2, arg3) { + wasm.__wbindgen_export_5(arg0, arg1, addHeapObject(arg2), addHeapObject(arg3)); } const EXPECTED_RESPONSE_TYPES = new Set(['basic', 'cors', 'default']); @@ -283,6 +283,9 @@ async function __wbg_load(module, imports) { function __wbg_get_imports() { const imports = {}; imports.wbg = {}; + imports.wbg.__wbg_addColorStop_02d04059a526a3f4 = function() { return handleError(function (arg0, arg1, arg2, arg3) { + getObject(arg0).addColorStop(arg1, getStringFromWasm0(arg2, arg3)); + }, arguments) }; imports.wbg.__wbg_addEventListener_775911544ac9d643 = function() { return handleError(function (arg0, arg1, arg2, arg3) { getObject(arg0).addEventListener(getStringFromWasm0(arg1, arg2), getObject(arg3)); }, arguments) }; @@ -315,6 +318,10 @@ function __wbg_get_imports() { const ret = getObject(arg0).createElement(getStringFromWasm0(arg1, arg2)); return addHeapObject(ret); }, arguments) }; + imports.wbg.__wbg_createRadialGradient_b10566e092cb7089 = function() { return handleError(function (arg0, arg1, arg2, arg3, arg4, arg5, arg6) { + const ret = getObject(arg0).createRadialGradient(arg1, arg2, arg3, arg4, arg5, arg6); + return addHeapObject(ret); + }, arguments) }; imports.wbg.__wbg_document_7d29d139bd619045 = function(arg0) { const ret = getObject(arg0).document; return isLikeNone(ret) ? 0 : addHeapObject(ret); @@ -450,6 +457,9 @@ function __wbg_get_imports() { imports.wbg.__wbg_setclassName_c8bccad917b973f4 = function(arg0, arg1, arg2) { getObject(arg0).className = getStringFromWasm0(arg1, arg2); }; + imports.wbg.__wbg_setfillStyle_9d745b4440df0b8b = function(arg0, arg1) { + getObject(arg0).fillStyle = getObject(arg1); + }; imports.wbg.__wbg_setfillStyle_a9ad5b25cf62a5bc = function(arg0, arg1, arg2) { getObject(arg0).fillStyle = getStringFromWasm0(arg1, arg2); }; @@ -530,7 +540,7 @@ function __wbg_get_imports() { }; imports.wbg.__wbindgen_cast_aaa93aae03c115ab = function(arg0, arg1) { // Cast intrinsic for `Closure(Closure { dtor_idx: 1, function: Function { arguments: [], shim_idx: 2, ret: Unit, inner_ret: Some(Unit) }, mutable: true }) -> Externref`. - const ret = makeMutClosure(arg0, arg1, 1, __wbg_adapter_9); + const ret = makeMutClosure(arg0, arg1, 1, __wbg_adapter_4); return addHeapObject(ret); }; imports.wbg.__wbindgen_cast_d6cd19b81560fd6e = function(arg0) { @@ -540,7 +550,7 @@ function __wbg_get_imports() { }; imports.wbg.__wbindgen_cast_e58c2e3d55f4d158 = function(arg0, arg1) { // Cast intrinsic for `Closure(Closure { dtor_idx: 1, function: Function { arguments: [NamedExternref("Array"), NamedExternref("IntersectionObserver")], shim_idx: 4, ret: Unit, inner_ret: Some(Unit) }, mutable: true }) -> Externref`. - const ret = makeMutClosure(arg0, arg1, 1, __wbg_adapter_4); + const ret = makeMutClosure(arg0, arg1, 1, __wbg_adapter_7); return addHeapObject(ret); }; imports.wbg.__wbindgen_object_clone_ref = function(arg0) { diff --git a/dist/railwayka_landing_bg.wasm b/dist/railwayka_landing_bg.wasm index 9c7bc77abfa6658996d266a2de3c57ed23d656ec..6b25673ae4739bf1dacd664b1ec6592245fefec9 100644 GIT binary patch delta 21615 zcmb7s4}4U`wf~)a_g{85$t8bCLPEH^L{0b;0>to7Aj5wYEr|cxVkHQ)1mtf-Ybl!o ztx>@S1~pn*BVvsTNE>RS1dWQCD%z;Dr7dk~AGK*qYucZ`*RHjt@HaBe& zo6Mi)Ox^j9xvJBOsp(>V`S4qAxns%aZ@G2-vYNVO*VZguQL}3HdL+wM*WI#Ybj9UW zRm&_EE&JV@V9f5;B_1O8yTKVXS;f5aaQq@`PdfswRe zFi2m^N(a?A0=ei@&|){%d!AxM6)B2Xk5D5AM0RVo3n(+CEhQ5wt`21q67(3Q)31dJYO(cY@ukSD-!2=>KaNDxm)~x@c zY4~odS+Uxfszfx~sxXf1isp#X>fOjdYmBiS8TGqJzBsTeIxI0Y?X$v=A~L3391xQp z6IXotE26eTw2AMF$uEgxV#=$cNjxmR@GbF8@eCyM4bdzf5s!)!qDveU%Xf>n#f)!@ z&CGwM!Tm>4pQEQuD;~)%GiZ9J7jGR6{ptD&mNAGvZO?#)UmlJzWw{>>&>F;^xeB zutAlYeP*>|+WB#7CfYO{tIFKxb1aEA?E>O-3;2)QljA;S-_$j71Efo;%r0 zjc!YD4+Pe`?Q`G%%RV}`^!0J5Ump;8|3(=LhyK-y!~+7AkvD&1TU z^o1u2O@CzR2@A|j527?+4?b@aKVmjpe6d6(@qWk`v*mahvRg2|X`yjuh2x)gC~cfs ziqsfqI*#A5Cz$z2GAEd}<0r!iq3kR5_4W2Riv-t=q55U0HXfAQwsjbGqo6^a#ds<0 zw&Y2lz0?Ugp;8kD0wGhS(+SiH%H34q9#oJ}uuhUlaxzikPNvY4Nv)l>O3jigvkjD> z#l+|-1Du@JQu7RVEl;FOquYBz_YU$C2|cMH?jw{sseZ?=IgO*xa6&WFLl9(cEKSXz5sHIO@PZZ-tU0m1St!-BfWE3AcF4HOEJ6a! z%|{ZhGINlmRbdiBm=X&k!jxbFLh=L&aZ)VJ36z?lbR;rClN6BATKlMQ0#qvpS)!x* z0S5z1M3GVjo)S!zJc$_zU>;>Jwb#J2cnYHI)3lRTJPiY3UnRRhE*#`T_7`btx=0Pv z;Vk;e+6T#CEJ=~V5y2bHOb;hmXlXL4h2|rkLNFrm>O+FjgHASlm4`;`5vUEFyct;! zRe>Q3xd%lOqq2)Z*U9EV9Cd2Lun0a5!$2Y2m;Iz5mzDtX1R+z|jbNf57f#ULCmg@M zm-O-@_GA$M;g$g~Nx>(Cdop^gf{pX~g{Sq_T$_baMRUm}Li~Xv*XF zpt+!ZhniJ3v=|Ol$oC23v#CNGll+7b7D(b2 zB0l+B!bI&Tz`qa}X6hEE{wE;>sO@2wBu@A+_2&pP7SsXx?7aZfnYy`O_aw`Gu2K-( z>^Yy1w^CqIAd!%4rzWVwkbIrMI2tx&6I%0=U!=-=Ab<8@3A2f{2S)8pZl7yx^Au?SDK*+uP>3yDBu3P@CuDib;%k$2yx8<&pj zXJsMzz@Y3x0lC4T1WP$cjx)jrG_1;uBAKw4F>seMgB%D}7DgD-h=uUQ%4=2gf*Fv` zEZS?yPU6uCs>YErF_&08?h2rj1%MqA2>_M`BL%5X_Ur(AQF)G%ppDH$so9~&f;lWT zkD+=rKO%b#cNrjN>tIWdZ71&60;;GoS0U*@3svS90Kuy-MUr@qF^d7B&LSkb&P{+~ zRpxa_9$iQ~*Mi5lD2E zQYR6RmsOc1z&ynyjwUHW@&qIDHG&oqT?dPZEF;keWUniE=8W9PA6?0xF|cGp{I1|b zkc^gm3rimUx;E~^a^m>ZHKT@C@*M1U=b(k>z}>m>95i2S4%C5BjunBGbd4&=>u)9X zpl74rRWT^B?J1Ht5lnM86SUtri9D@0ZIrTICO3w>vw&0N9lhRMrtBtYwtcZMN}HIg zt@lGEkj0YYi$__Pe0IXDCa4J`Q4d$7C&EtD?iA5M5l2I)-H6%|&l&D^hu+9TckK@> zhh%;&me4eL#;C;_pR#AvjwfnFBEbHOA;KfKxtm}3um95+slT=h$H-$no*ZMFHUkK; z)NH3=q&Z<4YhJ{K&`R1NZ?NjXX!aMd#9C}t6pK z&9PpPyO|{EUJroe0{6-!o_ke)9#c@luJmuzip>jhsw)MxcBR9|Uf@dmbw;B&A(F0C zq`1-n(1Jc!`gQb!y@5RKdZQ3Il0^{q2aRM3Hvxj%y$;FG88IJFF?p6yLLOzz9AMy| zW*}*0L^Ys%axEeG4MvOy1l_7cq8L#D2;Gc8@>eiWg;PX`j$S25{>TVyY-OA`w(3~8EWdQOql*XIz7|c_4ULe!sf|dx9Zl`*=GA99-5RiB8)Ivm!4zBSI&7Qkl9)m9F z8XYtXw4{)#!e{uLsFTK$2PC7Sm2n_^0 z2XQ#rSsY*GSWQnfv|(EsLf4IGhRz8rpWUu}8d*MeQa)kX1#caO^4YbqAZq<@d>bEOmcI7y zJzF<>EF;CUZPJeIPSV8mBo`^&_JG=yjik|t6{%m1i|KQQi=mnCW|E{^D;^(9V5<6^ zGfp!}szNU%D?7E^LlsQVS2zHOj3d#qm&!6ge*2#WdP_;#54+Pxg)+b}21&tPF zI+mo#52=ADd|8FwScPPf_Awp1JRgHS5&4)_Mv#x;jbkXeabyQVKIR}(;0R4#h+NEe zMv#jcpk2&A(HqX5yk|^QCpV21WtY-1Rn?1X2OWd?<*Xe1RPtycPL=FQ64~GOwpS+)!7${d*?=I&gSSHYiQgfabOUQnY)T5Nvi=bA) z5xULNls5Ytp+m&3M<~(6&LfSBwl=!$&>@n{dB zgFn>UnDNNN^m%@&J;e>u3JlZf8%6-9xEMuPDMV&JsNR|s&xTr?vInin3_DK3upiuY z#XxAgcaU^Xh5`E>1fU0dUEkk#v^?g6f>KXIV-~G~bXc5~F3f7IKEf`c5Hlu+Ld?Ci zN}2W#(U1W>FzriduCzNsoEp)em|zhH5<0YTfzR$cr|wHK*uERg=jr$d1eqFFC&r>h z)CugU0RyL?IB%g(9U{{rxli+r;}9(IAv?YUvF;Q`A_DGSB=tVO;%QJ^q++*QF(S7U zJC59s#I7?U_76nFh{$e=W8H2LD|%2AzIl&N@8^q}XyENU`Rk1(A+s@6-Q)ANE56_2f%`vrQB z3y`+c1kk3K)qyTBv<^H=!)Wx^mKd3le5lj=0&+V;wNtpUu#jpj0&@}MO|a(sreb-ozn1)4x_frGU7$k3@7Fker=jz zuXHTz_Z`9vcC#=~$_}CIG=XarsHbfFhN{l2Gm5V~W}8qx?(o|Db}oVs`7&g6DiLNvl)*l9{i`Neup(>3J?I!k(@E=G>ZS zLtAo?WEzsSlPODe?oE>X1;zRQx)|Yze^uM;S6nJfZ_v~bJCq@{>Hs-Fwqx3PMnIUP z1NaG0z%YHqL(&)m*TWpgX8W^*eFsHaPgzXI$g&uVIGOP!@*^bLlw8|7m$aM| z-B*jJJr>yhBuMX5!Rgz?4Ql)Jv6(lJ_wr+ed#Gf!dT07jal_+(oi1i-t@p{UG*azg ziq>aqt@p|OxL`1xY_0WBWik`4kkoE9Zss0y|3m6WGY@!L+b~Or>s_1w=ninsO?7JaFJUN0=8(DkdQJt*C2Q_)e2Ej(%LS^EldMORTGTI> z4uPDZS{FBye#94AQE_TpvTefoM%b_C3#y~CX9BG)*UT2>`&{;+YpF8oBkM1O!Sg=| z9A@5C+JfT1F%6Df5EF~krxuJOH{7sb1S#8d3mnRwTrgfNPy?==YaTwT7F|2dYM@Jrf`R$rZt4U0Yk>l^pON2}wwQo^q4 z3(~BUXvn_qJ!*r^)>YAfzIQ{_bm}2UxBtPu z9s*tuMqdxraonJR$l6#J4 z8|8X$+L1+_!S+9uj)tj^_M_^dPmi6|sX4~Wi%sjCU|}2qQ!Hv4%bXuaJwXfmRXFe< zqa{l%9HSBlNH!f&_Gdg(e zk5y)S3jPqoZHzybLes`@2jh>Y&~z}|$@mjT64Zev>g0khE;yA!)Wz^g#-B-{Imz&8 z#-B~0In6M*+{ZvS6MU3H+?|3?^l+w!iO!|Ky$ts)S~T+f(2Mh8q~a zI|XiJxRLRDQs5?rn-W~GPiGizX1JN*{V8w@!!3+I%@w*w;Gz|0Q&(qnxKV|A$b#yki%bXy zSu(u8+&l_KrQ)9(XLEbbg>BsPxe`!TBd|}QB59PF%}1)one=7=uP|_RMVH+DEfka? zM87}>4q5TlpFekF(aq5iodtS@=MNFkOuE6ETi6Y5x}~-poXkqcanbcjLKOo(R6@zV|`7Fl&04$=BBqVo|xCpLUX+j{8?=r-uBp0 zRlj7=C>#m{{3HqvF~;>FGjk<6&Af`dCXIxBB?0h`m)2Zr!!1Gpf*QhBx)fis)!kTqo(-EuA|ja3oJP3Ku<4w+G=VZ2W2o% z97zG+O^=>5q03S!FB+N<%#B)d$q3NLL4P&7d>#s%{3lD`Qu{DQvzeY;c+1RlOQu4! z*h`5N(WWk518ybJwvM>z0%j5iyfZ{50Pua&qj-%3x2%@KMX*CSTOMTvn)$MEyxCcPN}`woC8 zzXgdBKiH_6BtBD~_$u}^4T4nUPKvEVbxO@mam2Zill-CvZCS43$TJ|9MTiXGEnAat zEWE4{35nP%-;oQc1CjM#OE$VT*=SwAMmYk-F?LH{v6hsQBa{?slZ{mU9_DEkVk=V5OR*yd@BG%NlMCt2 z0O1S`BjgSH11wKc@S8_>lNO;X5$b~Vk7*L5i5MomX+fJUdXjNR1jvAcAR z%tam6sC=Lfxv2dbWdqgXqF79%74G2C773H0OyHe}FwI&>u3#W2`zA+BMiC@+@o~~o zf*)M5D#3-7ns(fhCmNtf18vK(RM%aD6ZFD?qQ^A-@EK=ON)OF2X^RkFM{-jfLEPb% zJ;UHn&(!8Po<||l3mL}KWS|alw#*qdW3I0l_SDd+dt-JoHx{`8$c>y{^vB;+4MHv} znHz>&Hrhy-PCOhlt!mT#M{k&5HL$mM&WwL-u5GVVcTU~w40z1`slcPIY=^DKPvyCN z<<0g<5gUk7ug({y?qyt_ljV4Hj6*B=z~#(1_tanByLw4tz9s~bMj-Fl)LFAT;9el| zTsTy{*U9gLo1IK2v)LKw3~a_HK9HEm1cUjt@rV;4=aD&MEPq}_FEf_&=g(93k^l{7 zAdM(75cGB}F1MpZKk(x81NlALa6C57qq#6J1a!KWy5HOUXuQB>$*5kMF4z@AsnckW z9fpF&D5MGRM>2*tGie=4iQF&X8&4V9HqjXx@R;FBI7gsmbQD3G#E}V1pl&6IJB)K-BVq94FSLxe#nAT> zu#f%|)IE`)6Aq#xTH+Ku9w&Kg=|v#{AV~Ic5|3^MN|{fKpD8Kig`EQ)NG2Z%vX|h? z13bwhJ%^)9K*Q&guPz}?hR2h8z;A$@HhTuTT1eNrX<-M#BN%Q~#BxYQOJli+53{af z+A%%xfyu#xUrg*PG{QuR!=al4p9T{@T> zzBB`mxTZigEQIV35O;)w2+*4-obnk@ZbhE_3b`+KD>?UU8;B_)J0vABI-nNV+B$GE8}>>3V!eeTf|X;YK7c}ohUU) zlLHaKx4I1XU#{v!Vw^=%l^E|?O1)|Oh-Z?fjULwQL#kVe9y_T!dz5s%9twPnpV5Ddk37z>uSB)lZepU`gh>{5wQl!qgOt zhq&lzI7Kx`90zHagf$HQ7c!*P-w?aSHy zpuQ)L;};djaV-vgU-kPGalj(&bdRhc>F3pV07%j4Mg zIPS+Vrp!lE=9ksvWywdUJL$>&Bf5j;Vc~a>%I$cD>TWorv>?!k6QMXZLHzPq5Md7O ziRj@m%6LmkfOa>Kk`}S&mB>}{=9BlheH%2q^r34HSQhGDA-kVLw}*uhkv(*qG(fgN zx9R=^`;*)RIrLmw-b^RQ^W_kIskemAF!p#gfPZ-He`DSRYw9|>F@qka7ChAP?c zH!;1nsBUMVHN8IO6I)wHZTpcq+KY{2Rr5lLXeSvPr%>p72O*ciUW8Ru-hF%aMQW+` zyElq|s<9297B{LL4RslO;G~xTm^Yl^GVi%md`4B>GgDlrHr*rXtoPDAce`;iOdawI z?yV}k&cWPxr#W1^!$7V|#|@fgPg8sEogn6^Q}@oFGY>-r+5Yc>vvPR~iF-e!5qnxa z#J{0XYwsHo;lmqg500!)-ZvrS-Q270`(jb|avl%yaI2lW-N`)fUR=%C?p%J}?Y9#y zHRrGzVv9qIV~Eb^VP08;Oun>uc)OE-_&bEgctb!$a9dar@SFe* zmFV^yx|}z4dz(OV4m$xjD*VWSXf0f+AKWn{i!pElLV9mP)US4w< zMbuqt$o)gYR0Uaj+C1m}Aqj2)r%m1XM;?GvqQ;zM081}iMilZxAR1Iclxbf{w|WqqqaPs2Q-rpX z=nlihcN5;9#MisO{gLMgAMV4OF8#hH;Ij#jLF1Bd5E&NE>)yRU2D!XGZq?S^^T`T-95k3_oEmWN73x_aiJQhx^G zX_@NeLzgYEXQso3urVG$0W!SR#`6riYzRTRSMbeQA*|3My9`MEV9m|~?*Wbk5M>ah zutX%Zv3Oa{ZyJ^cQ^Kr5sBp9$qw`HVEjb3No|!2UvDCbxH5Y|9e*l=?hj; z9PDV9kEU!`J*7FcSFz{}LRM(e&f+>Gdz5WZhX!Tb|zf5Z<;ISh&5vR`f4Kl&QFiKBQj7vg8Ow1c5%!N!$^I32}; zaIt7JC=>HQ13NOMG191iv3d}+b6Om~n&h~|$p^swy&|GE9~hPedJ28Wlh_r)e_oqz zsI~)xS5T;+7j*K+*b~YjwX&Ns-4CMXD&By>Gy<}d_K<7om>z;fQ;3z{OQIu+@WU$f zF^sPzLk@6yZNd`8Z8+GWsu#ao(@*mQWD{wm`IW8xZ6Y9H6G19j*}9ml;O*7|vWf22 zQIsn%tritHwZ>HF> zf%(QO1%&6GrXyDrbBcs~l}5mukc!wqz-JU8IrFs2cy4ai@n?u0o`ar#Ed@SZt#~e$ zZ6BECd<{9L_Q1Ar7G_&!sBbW=SEH#=ICzfDpyr)|=Zli$V!#bkX8n%+u_ULznmL>|%z)!a5Gv*`u+9(qzo z7K5AMzqO4FLm-Y1mjZ{6ww6C15n`E|_`*r&UDL846#l_^1xM6jZrBQ;o)0VHm(`df zC9y5S5fpzxz^2S{I5twmE|m{FroCBhJmTbeR5%b)IEMn+M5Xp0DJn%M%L(X%LdO=! zr!XGiUl_w3(eVk#rFJ?lHL9K?R|fVFxJp&G7Y6ogu%>-rpc_{N_7e5w_Od}AF-TQQ z&7cx$Xd|BxHr3CnG)r zRdqsF6~?i2NqXEYX5m`h#f1)Rj)yr6WH{j`<7v2eN0bI_Tt&N@Si(e)@EI^x*sgyS z={HXq&Yd}qk9-#ba`Zbj`V}phpkLzV)Y_j%HT^?d3TXl&u_3|XmKPI(aImI*DI5$1 z2z)v|gcczKI*`zQ)eKX40Hy+;aQekYk*n6dH2hQgQ6+o}8I}!K1eNe!RMOGaXFrcA zB43Y)BgJi^Nc4ls{+0A=O7+K=zMS&{@0sz80Rw`5tcv^WIcihKtf5^vPZ2kM>MRQJ z`QR7nj76sUcVU_dziK)B?_lXUv z_T}QhesbZ5)%`C!>PxQ-8d?rjAt%f(*nXKLf>2fk5}q(qc7IQ`y>fNtwNQA_RnmXs z?M{{R>Ll@in*VBX)*MWlsec1ZlV#cusQOpGCT>;1V`KB`@v_x^m)sRxI_6XMJj>lL zIJP>gh_yV9bp{T8q>*Odrrtf4ofv!p+K6lx7A>mvxS=zl_n<~>13Q(N0oTYI7x;He zX0D6-WW{>yetv=wrB8hHONhZ*LUJXe^=WTzozJjU2{s%NBIwUhw z|9R|*k{hc&7&(pgN{HSmKq|X6jtB(f~t6Za2Ny*Jyo`Urfz(FggB=D{Ca`<=IfW3 zJB9kp>t*KYXVr(VPp&2H`n;A6Z8%B{Sfh_R!MJpP_=6jS#D+%)@#$w7F!5R`;7T6g zy=^G&rx1&tJc{!;23_=%Y0;(z(pJk%cbJ%^3l+hvero2Djo&dAd7ZYVazO=+FXP+#vPsUGSal-2eWnHl0zRG5Q7 zhSjNL;i>ZrBUBhC8O;&G-IVz-pHNb`?n)>FU7F$P`N|($iN))=A50BTgp(xk0QvC` zCWptRW{1z7muyB*GoXWvFlpF`!D~XXYe@32rnsRU75}W0Fj3jPg%qDHL9KkVJTw+6 z!Tmh;W@UJM3_R)Vuil&#o{*Xyu0HiveyEClC)ir^R>>7I$%o$?4&2!ow?#w~wdce% z>Scsx5h~9PO6_=SLK%*fkOFCfG20QNM20ORGrYYFG>MFiR=*1M;ah7U`&*8ehIuoH zQQJ?coySYWIyLH@A%6M`8SB;0j*k@2s?ggvi;Zge+i^Aj?c6~d+2%3V&~54+s>B*4 zLn`t1(7bJMLwY9JJ8N0mJJs`V$MW{UM_jDzFK=I(H%I?P7%LO+*hfPQuxI*X4yyc} z60u$_e5WF^J`x$`%115k95@)0WPt{b>9a;;n4xEg1E!{ZyL$PZ>0+1i|8QjJN0^&3 zRHSjur9Wsv4S{nk_ViZ|kQV7be1JpYLC!n$ClL%<$?(hfGHRJj)>CN~;8W`A9~P$f z(#sBMkXP|t(MZpwW5R~=# zU7AQJIw_$&AlHb*&+G4}U4skGr)Juq5gDQ~-!1fiRYY89hX*ATAV-+|TW?<+Qh=h_ zll9(+bfgpd92o@ZVIgE`k#cLP8IWRRFmpkb=!YCEW&Y1+-;b6HlR_lfkje@A+d`yK zkvyuIg$oyYON@@~8==bvoX7L;7G`0}in--Jd4BM2d3Ngfcx;xTroA`J!nCPJ-y5x( z-wTT2s`0%%F+z2`SDbM#RG|Q^lV!iZTb+F`p6wlSlKAaUso4AZ=0i`ZN$)%Ju+fWT zQP1A*OTaXk$-+P!gBFTu0*eInATogY<1vGVM$7fci!joDQa$L-i>U$A)m5iO!xVQ`TgV~>mk2r-J1GQ<9q&R!F-pbC+_6EQpd zr?B|myR5it!T512`YZPX$SBR?i3|DrIA!N>#ce)=HCFn&K2*dEjc znX&%!OKM6luNdKsx%~1G&S-*+b12J3*_lBXrAZJ`MH$x|U6HIho~jzg<-#^{QYvp) zf9t4KE0&b6-(VPvP!>knWB5Aw_B?uji?eW9UEPY+pLcFw>#VI=U$^4cRm+@PYgTWp z*-&0yt^p4}lCy~oJ&&qJXFAh38&=%4Y@&0gVLXe*v(V_vNNHrh+4EJ8re^KhWviDi zTk6!Uah9xE`o%FzQSLF*1DKfd@_z%Io09JZJRjelN4G!fEL>Z2M`ATva#pNfQHQ@M zm*jbaQDWNgb%rq-DKX;UTZ(T8-x$7ee7#P5;Ba6{z7+Wp$kWtB@udkb!S@n;*Ds?n zqWgQD`6M89{Kt8TWJ~_@S_&dxfLf64en+leaa&E@iZ!d9RcqF)bvD$Y{<5VpkBf*) z>*b@!Q?FhgQDTGCujkR-+nibJYi?WSjBt3w37V!2MulY?5fDs5N;)@;@(AaP_--U%BSADSB&${|UpCoTjJl-NcOa$Ve+j7{X}z0%6=@Lp?UW_} z7(C6XYR)ppe1dI!Jf)|c1D-sLho|&ncvzr|rZA`oFYh2s{Y!=v; zfg_V`%2KtzoifHlKMNGijh7FjItjGsW!r4lN7TCC7T8N}U;f#Oo1H1nlFKSCGfrizS3a0#A_@F% zn)yVIy7G5%vm-~X{@wDynYmaI(d;OsBoz9PUC?)=`pfUeWi3aEjoe10WH~!>)x_?2 zxraXF7Iz>ees{R(M8~rb!#JDUdT)2RFvEH3h2P(0-kYbY{xC7?ojl#}exz~K>@HAS z{!nX<$ya~=!;)c3^KD}hupt-hiT zQz$7vJ0`rpz-ATb9i)DC_BUAzvBWF~?Ph#Q#tR3jcm6ae{S?sTHhBe7%g$~{?*(Qp zFy#>LfY$&2r<+Bv3xTUhwV{@MI4TWT{)|yOKg<@B)Yp5IdBu-ZV~-{{SOf&bY%bl delta 18375 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 Dm(=6# diff --git a/dist/railwayka_landing_bg.wasm.d.ts b/dist/railwayka_landing_bg.wasm.d.ts index 49d0bbf..17d4b5f 100644 --- a/dist/railwayka_landing_bg.wasm.d.ts +++ b/dist/railwayka_landing_bg.wasm.d.ts @@ -6,6 +6,6 @@ export const __wbindgen_export_0: (a: number) => void; export const __wbindgen_export_1: (a: number, b: number) => number; export const __wbindgen_export_2: (a: number, b: number, c: number, d: number) => number; export const __wbindgen_export_3: WebAssembly.Table; -export const __wbindgen_export_4: (a: number, b: number, c: number, d: number) => void; -export const __wbindgen_export_5: (a: number, b: number) => void; +export const __wbindgen_export_4: (a: number, b: number) => void; +export const __wbindgen_export_5: (a: number, b: number, c: number, d: number) => void; export const __wbindgen_start: () => void; diff --git a/src/lib.rs b/src/lib.rs index c16c349..bc97005 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -22,49 +22,78 @@ struct Particle { impl Particle { fn new(x: f64, y: f64, hue: f64) -> Self { - let angle = js_sys::Math::random() * std::f64::consts::PI * 2.0; - let speed = js_sys::Math::random() * 0.5 + 0.2; Self { x, y, - vx: angle.cos() * speed, - vy: angle.sin() * speed, - size: js_sys::Math::random() * 2.0 + 1.0, + vx: 0.0, + vy: 0.0, + size: js_sys::Math::random() * 2.0 + 2.0, life: 1.0, - max_life: js_sys::Math::random() * 100.0 + 100.0, + max_life: js_sys::Math::random() * 500.0 + 500.0, hue, } } fn update(&mut self, width: f64, height: f64, time: f64) { - // Flow field influence using sine waves for fluid motion - let flow_x = ((self.y * 0.01 + time * 0.0005).sin() * 0.5).sin(); - let flow_y = ((self.x * 0.01 + time * 0.0003).cos() * 0.5).cos(); + // Multiple layered flow fields for complex fluid motion + let scale1 = 0.003; + let scale2 = 0.006; + let scale3 = 0.001; - self.vx += flow_x * 0.1; - self.vy += flow_y * 0.1; + // Layer 1: Large sweeping currents + let angle1 = (self.x * scale1 + time * 0.0002).sin() * 3.0 + + (self.y * scale1 + time * 0.0001).cos() * 3.0; - // Damping for smooth motion - self.vx *= 0.98; - self.vy *= 0.98; + // Layer 2: Medium turbulence + let angle2 = (self.x * scale2 - time * 0.0003).cos() * 2.0 + + (self.y * scale2 + time * 0.0002).sin() * 2.0; + // Layer 3: Fine detail + let angle3 = ((self.x * scale3 + time * 0.0001).sin() + + (self.y * scale3 - time * 0.00015).cos()) * 1.5; + + // Combine flow fields + let angle = angle1 + angle2 + angle3; + + // Convert to force + let force = 0.15; + let fx = angle.cos() * force; + let fy = angle.sin() * force; + + // Apply force with gentle acceleration + self.vx += fx; + self.vy += fy; + + // Smooth damping for fluid motion + self.vx *= 0.95; + self.vy *= 0.95; + + // Limit maximum velocity for smooth flow + let max_speed = 2.0; + let speed = (self.vx * self.vx + self.vy * self.vy).sqrt(); + if speed > max_speed { + self.vx = (self.vx / speed) * max_speed; + self.vy = (self.vy / speed) * max_speed; + } + + // Update position self.x += self.vx; self.y += self.vy; self.life -= 1.0; - // Wrap around edges with smooth transition - if self.x < 0.0 { - self.x = width; + // Wrap around edges smoothly + if self.x < -10.0 { + self.x = width + 10.0; } - if self.x > width { - self.x = 0.0; + if self.x > width + 10.0 { + self.x = -10.0; } - if self.y < 0.0 { - self.y = height; + if self.y < -10.0 { + self.y = height + 10.0; } - if self.y > height { - self.y = 0.0; + if self.y > height + 10.0 { + self.y = -10.0; } } @@ -74,18 +103,30 @@ impl Particle { fn draw(&self, ctx: &CanvasRenderingContext2d) { let alpha = (self.life / self.max_life).min(1.0); - let color = format!("hsla({}, 70%, 50%, {})", self.hue, alpha * 0.8); + // Glow effect + let glow_gradient = ctx.create_radial_gradient( + self.x, self.y, 0.0, + self.x, self.y, self.size * 3.0 + ).ok(); + + if let Some(gradient) = glow_gradient { + let alpha_hex = format!("{:02x}", (alpha * 60.0) as u8); + gradient.add_color_stop(0.0, &format!("#{}", alpha_hex.repeat(3))).ok(); + gradient.add_color_stop(0.5, &format!("rgba(50, 255, 150, {})", alpha * 0.3)).ok(); + gradient.add_color_stop(1.0, "rgba(50, 255, 150, 0)").ok(); + + ctx.set_fill_style(&JsValue::from(gradient)); + ctx.begin_path(); + let _ = ctx.arc(self.x, self.y, self.size * 3.0, 0.0, std::f64::consts::PI * 2.0); + ctx.fill(); + } + + // Core particle + let color = format!("rgba(100, 255, 180, {})", alpha * 0.8); ctx.set_fill_style_str(&color); ctx.begin_path(); - ctx.arc(self.x, self.y, self.size, 0.0, std::f64::consts::PI * 2.0).ok(); - ctx.fill(); - - // Add glow effect - let glow_color = format!("hsla({}, 70%, 60%, {})", self.hue, alpha * 0.3); - ctx.set_fill_style_str(&glow_color); - ctx.begin_path(); - ctx.arc(self.x, self.y, self.size * 2.0, 0.0, std::f64::consts::PI * 2.0).ok(); + let _ = ctx.arc(self.x, self.y, self.size, 0.0, std::f64::consts::PI * 2.0); ctx.fill(); } } @@ -105,7 +146,7 @@ impl ParticleSystem { particles: Vec::new(), width, height, - max_particles: 800, + max_particles: 1200, time: 0.0, } } @@ -173,6 +214,8 @@ pub fn main() -> Result<(), JsValue> { } fn setup_particle_canvas(document: &Document, body: &HtmlElement, window: &Window) -> Result<(), JsValue> { + console::log_1(&"🎨 Setting up particle canvas...".into()); + // Create canvas element let canvas = document .create_element("canvas")? @@ -183,10 +226,13 @@ fn setup_particle_canvas(document: &Document, body: &HtmlElement, window: &Windo let width = window.inner_width()?.as_f64().unwrap_or(800.0); let height = window.inner_height()?.as_f64().unwrap_or(600.0); + console::log_1(&format!("📐 Canvas size: {}x{}", width, height).into()); + canvas.set_width(width as u32); canvas.set_height(height as u32); body.append_child(&canvas)?; + console::log_1(&"✅ Canvas appended to body".into()); // Get 2D context let context = canvas @@ -198,18 +244,40 @@ fn setup_particle_canvas(document: &Document, body: &HtmlElement, window: &Windo let particle_system = Rc::new(RefCell::new(ParticleSystem::new(width, height))); // Spawn initial particles - particle_system.borrow_mut().spawn_particles(400); + particle_system.borrow_mut().spawn_particles(600); + console::log_1(&format!("🌟 Spawned {} initial particles", particle_system.borrow().particles.len()).into()); // Setup animation loop let system_clone = particle_system.clone(); let context_clone = context.clone(); + let frame_count = Rc::new(RefCell::new(0u32)); + let window_clone = window.clone(); let animate_closure = Rc::new(RefCell::new(None::>)); let animate_clone = animate_closure.clone(); + let frame_clone = frame_count.clone(); *animate_closure.borrow_mut() = Some(Closure::wrap(Box::new(move || { - // Clear canvas with trail effect (don't fully clear for fluid trails) - context_clone.set_fill_style_str("rgba(10, 14, 23, 0.08)"); + *frame_clone.borrow_mut() += 1; + + if *frame_clone.borrow() == 1 { + console::log_1(&"🎬 Animation loop started!".into()); + } + + if *frame_clone.borrow() % 60 == 0 { + let sys = system_clone.borrow(); + console::log_1(&format!("🔄 Frame {}, {} particles", + *frame_clone.borrow(), + sys.particles.len()).into()); + + if let Some(p) = sys.particles.first() { + console::log_1(&format!("🔍 First particle: x={:.1}, y={:.1}, vx={:.2}, vy={:.2}, size={:.1}, life={:.1}", + p.x, p.y, p.vx, p.vy, p.size, p.life).into()); + } + } + + // Semi-transparent clear for fluid trails + context_clone.set_fill_style_str("rgba(10, 14, 23, 0.12)"); context_clone.fill_rect(0.0, 0.0, width, height); // Update and draw particles @@ -218,7 +286,7 @@ fn setup_particle_canvas(document: &Document, body: &HtmlElement, window: &Windo // Request next frame if let Some(closure) = animate_clone.borrow().as_ref() { - window + window_clone .request_animation_frame(closure.as_ref().unchecked_ref()) .ok(); }