From db593cd2992d70d6169cb3f7f5571755bf61a6ab Mon Sep 17 00:00:00 2001 From: rail Date: Sat, 22 Nov 2025 23:02:22 +0300 Subject: [PATCH] beauty, but not for demo... --- dist/railwayka_landing.js | 30 ++-- dist/railwayka_landing_bg.wasm | Bin 65291 -> 62214 bytes src/lib.rs | 308 +++++++++++++-------------------- 3 files changed, 139 insertions(+), 199 deletions(-) diff --git a/dist/railwayka_landing.js b/dist/railwayka_landing.js index 2e16c44..58c717f 100644 --- a/dist/railwayka_landing.js +++ b/dist/railwayka_landing.js @@ -237,11 +237,11 @@ export function main() { wasm.main(); } -function __wbg_adapter_4(arg0, arg1) { +function __wbg_adapter_8(arg0, arg1) { wasm.__wbindgen_export_4(arg0, arg1); } -function __wbg_adapter_7(arg0, arg1, arg2, arg3) { +function __wbg_adapter_11(arg0, arg1, arg2, arg3) { wasm.__wbindgen_export_5(arg0, arg1, addHeapObject(arg2), addHeapObject(arg3)); } @@ -296,9 +296,6 @@ function __wbg_get_imports() { const ret = getObject(arg0).appendChild(getObject(arg1)); return addHeapObject(ret); }, arguments) }; - imports.wbg.__wbg_arc_61cbec33cc96a55e = function() { return handleError(function (arg0, arg1, arg2, arg3, arg4, arg5) { - getObject(arg0).arc(arg1, arg2, arg3, arg4, arg5); - }, arguments) }; imports.wbg.__wbg_beginPath_119487ebd04e9e1c = function(arg0) { getObject(arg0).beginPath(); }; @@ -314,14 +311,17 @@ function __wbg_get_imports() { const ret = getObject(arg0).classList; return addHeapObject(ret); }; + imports.wbg.__wbg_closePath_58530240bb00a7fc = function(arg0) { + getObject(arg0).closePath(); + }; imports.wbg.__wbg_createElement_4909dfa2011f2abe = function() { return handleError(function (arg0, arg1, arg2) { 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); + imports.wbg.__wbg_createLinearGradient_098463fca2d0190f = function(arg0, arg1, arg2, arg3, arg4) { + const ret = getObject(arg0).createLinearGradient(arg1, arg2, arg3, arg4); return addHeapObject(ret); - }, arguments) }; + }; imports.wbg.__wbg_document_7d29d139bd619045 = function(arg0) { const ret = getObject(arg0).document; return isLikeNone(ret) ? 0 : addHeapObject(ret); @@ -421,9 +421,15 @@ function __wbg_get_imports() { const ret = getObject(arg0).length; return ret; }; + imports.wbg.__wbg_lineTo_d9b895383c2303ba = function(arg0, arg1, arg2) { + getObject(arg0).lineTo(arg1, arg2); + }; imports.wbg.__wbg_log_6c7b5f4f00b8ce3f = function(arg0) { console.log(getObject(arg0)); }; + imports.wbg.__wbg_moveTo_a0b1ec729ba8ee5d = function(arg0, arg1, arg2) { + getObject(arg0).moveTo(arg1, arg2); + }; imports.wbg.__wbg_new_19c25a3f2fa63a02 = function() { const ret = new Object(); return addHeapObject(ret); @@ -443,10 +449,6 @@ function __wbg_get_imports() { const ret = getObject(arg0).querySelectorAll(getStringFromWasm0(arg1, arg2)); return addHeapObject(ret); }, arguments) }; - imports.wbg.__wbg_random_7ed63a0b38ee3b75 = function() { - const ret = Math.random(); - return ret; - }; imports.wbg.__wbg_requestAnimationFrame_ddc84a7def436784 = function() { return handleError(function (arg0, arg1) { const ret = getObject(arg0).requestAnimationFrame(getObject(arg1)); return ret; @@ -540,7 +542,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_4); + const ret = makeMutClosure(arg0, arg1, 1, __wbg_adapter_8); return addHeapObject(ret); }; imports.wbg.__wbindgen_cast_d6cd19b81560fd6e = function(arg0) { @@ -550,7 +552,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_7); + const ret = makeMutClosure(arg0, arg1, 1, __wbg_adapter_11); 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 6b25673ae4739bf1dacd664b1ec6592245fefec9..3101340a82077e53e590736608a61bad870a4846 100644 GIT binary patch delta 20521 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 Z^wST;m1^{-{rp$i)2ha)!~Z?|{{U7>8o>Yn diff --git a/src/lib.rs b/src/lib.rs index bc97005..d208ace 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -8,180 +8,141 @@ use web_sys::{ use std::cell::RefCell; use std::rc::Rc; -// Particle structure -struct Particle { - x: f64, - y: f64, - vx: f64, - vy: f64, - size: f64, - life: f64, - max_life: f64, - hue: f64, +// Wave layer for fluid simulation +struct WaveLayer { + amplitude: f64, + frequency: f64, + speed: f64, + offset: f64, } -impl Particle { - fn new(x: f64, y: f64, hue: f64) -> Self { - Self { - x, - y, - vx: 0.0, - vy: 0.0, - size: js_sys::Math::random() * 2.0 + 2.0, - life: 1.0, - max_life: js_sys::Math::random() * 500.0 + 500.0, - hue, - } - } - - fn update(&mut self, width: f64, height: f64, time: f64) { - // Multiple layered flow fields for complex fluid motion - let scale1 = 0.003; - let scale2 = 0.006; - let scale3 = 0.001; - - // 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; - - // 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 smoothly - if self.x < -10.0 { - self.x = width + 10.0; - } - if self.x > width + 10.0 { - self.x = -10.0; - } - if self.y < -10.0 { - self.y = height + 10.0; - } - if self.y > height + 10.0 { - self.y = -10.0; - } - } - - fn is_dead(&self) -> bool { - self.life <= 0.0 - } - - fn draw(&self, ctx: &CanvasRenderingContext2d) { - let alpha = (self.life / self.max_life).min(1.0); - - // 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(); - let _ = ctx.arc(self.x, self.y, self.size, 0.0, std::f64::consts::PI * 2.0); - ctx.fill(); - } -} - -// Particle system -struct ParticleSystem { - particles: Vec, +// Fluid wave system +struct FluidWaves { width: f64, height: f64, - max_particles: usize, time: f64, + layers: Vec, } -impl ParticleSystem { +impl FluidWaves { fn new(width: f64, height: f64) -> Self { + // Create multiple wave layers with different properties (faster speeds) + let layers = vec![ + // Larger, slower primary waves for big curves + WaveLayer { amplitude: 0.25, frequency: 0.001, speed: 0.0008, offset: 0.0 }, + // Secondary shape definition + WaveLayer { amplitude: 0.18, frequency: 0.0018, speed: 0.0015, offset: 1.5 }, + // Counter-movement for interest + WaveLayer { amplitude: 0.12, frequency: 0.003, speed: -0.0012, offset: 3.0 }, + // Detail waves + WaveLayer { amplitude: 0.08, frequency: 0.005, speed: 0.002, offset: 4.5 }, + // Fine detail + WaveLayer { amplitude: 0.05, frequency: 0.008, speed: -0.0025, offset: 2.0 }, + ]; + Self { - particles: Vec::new(), width, height, - max_particles: 1200, time: 0.0, - } - } - - fn spawn_particles(&mut self, count: usize) { - for _ in 0..count { - if self.particles.len() < self.max_particles { - let x = js_sys::Math::random() * self.width; - let y = js_sys::Math::random() * self.height; - // Green hues: 120-160 (emerald to lime) - let hue = js_sys::Math::random() * 40.0 + 120.0; - self.particles.push(Particle::new(x, y, hue)); - } + layers, } } fn update(&mut self) { self.time += 1.0; + } - // Update existing particles - for particle in &mut self.particles { - particle.update(self.width, self.height, self.time); + // Calculate wave height at a given position with randomness + fn wave_height(&self, x: f64, y: f64, randomness: f64) -> f64 { + let mut height = 0.0; + + for layer in &self.layers { + // Multiple sine waves at different frequencies for organic curves + let wave1 = (x * layer.frequency + self.time * layer.speed + layer.offset).sin(); + let wave2 = (x * layer.frequency * 1.7 - self.time * layer.speed * 0.5).sin(); + let wave3 = (x * layer.frequency * 2.3 + self.time * layer.speed * 1.2 + layer.offset).cos(); + + // Vertical component for depth + let wave_y = (y * layer.frequency * 0.4 - self.time * layer.speed * 0.6).cos(); + + // Combine with noise-like variation + let combined = (wave1 + wave2 * 0.5 + wave3 * 0.3 + wave_y * 0.4) * layer.amplitude; + height += combined * randomness; } - // Remove dead particles - self.particles.retain(|p| !p.is_dead()); - - // Spawn new particles - let spawn_count = (self.max_particles - self.particles.len()).min(5); - self.spawn_particles(spawn_count); + height } fn draw(&self, ctx: &CanvasRenderingContext2d) { - for particle in &self.particles { - particle.draw(ctx); + // Draw smooth gradient waves at the bottom + self.draw_smooth_waves(ctx); + } + + fn draw_smooth_waves(&self, ctx: &CanvasRenderingContext2d) { + let num_waves = 12; + let wave_section_height = self.height * 0.6; // Bottom 60% of screen + let start_y = self.height - wave_section_height; + + // Draw from back to front for proper layering + for i in (0..num_waves).rev() { + let progress = i as f64 / (num_waves - 1) as f64; + + // Each wave layer at different depths + let layer_offset = progress * wave_section_height * 0.9; + let base_y = start_y + layer_offset; + + // Varying amplitude for each layer (more variation in front) + // Increased amplitude for "curvier" look + let amplitude = 40.0 + progress * 80.0; + + // Randomness factor increases for front layers + let randomness = 0.8 + progress * 0.4; + + ctx.begin_path(); + ctx.move_to(0.0, base_y); + + // Draw smooth wave curve - increased points for smoothness + let points = 300; + for j in 0..=points { + let x = (j as f64 / points as f64) * self.width; + let y_offset = self.wave_height(x, base_y, randomness) * amplitude; + let y = base_y + y_offset; + + ctx.line_to(x, y); + } + + // Close the path to bottom + ctx.line_to(self.width, self.height); + ctx.line_to(0.0, self.height); + ctx.close_path(); + + // Create gradient for depth effect + let gradient = ctx.create_linear_gradient(0.0, base_y - 80.0, 0.0, self.height); + + // Back layers are more transparent and darker (3D depth) + // Front layers are more opaque and brighter + let alpha_top = 0.05 + progress * 0.25; + let alpha_bottom = 0.1 + progress * 0.3; + + // Deep ocean colors + // Hue shift: Deep Blue (220) -> Teal/Cyan (160) + let hue = 220.0 - progress * 60.0; + let saturation = 50.0 + progress * 20.0; // 50-70% + let lightness_top = 15.0 + progress * 20.0; // 15-35% + let lightness_bottom = 10.0 + progress * 15.0; // 10-25% + + let _ = gradient.add_color_stop(0.0, &format!("hsla({}, {}%, {}%, {})", + hue, saturation, lightness_top, alpha_top)); + + // Middle stop for better volume/highlight + let _ = gradient.add_color_stop(0.4, &format!("hsla({}, {}%, {}%, {})", + hue - 5.0, saturation + 5.0, lightness_top + 5.0, alpha_top * 1.2)); + + let _ = gradient.add_color_stop(1.0, &format!("hsla({}, {}%, {}%, {})", + hue - 15.0, saturation, lightness_bottom, alpha_bottom)); + + ctx.set_fill_style(&JsValue::from(gradient)); + ctx.fill(); } } @@ -240,47 +201,24 @@ fn setup_particle_canvas(document: &Document, body: &HtmlElement, window: &Windo .unwrap() .dyn_into::()?; - // Initialize particle system - let particle_system = Rc::new(RefCell::new(ParticleSystem::new(width, height))); - - // Spawn initial particles - particle_system.borrow_mut().spawn_particles(600); - console::log_1(&format!("🌟 Spawned {} initial particles", particle_system.borrow().particles.len()).into()); + // Initialize fluid wave system + let wave_system = Rc::new(RefCell::new(FluidWaves::new(width, height))); + console::log_1(&"🌊 Fluid wave system initialized!".into()); // Setup animation loop - let system_clone = particle_system.clone(); + let system_clone = wave_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 || { - *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)"); + // Clear canvas + context_clone.set_fill_style_str("rgba(10, 14, 23, 1.0)"); context_clone.fill_rect(0.0, 0.0, width, height); - // Update and draw particles + // Update and draw waves system_clone.borrow_mut().update(); system_clone.borrow().draw(&context_clone); @@ -299,12 +237,12 @@ fn setup_particle_canvas(document: &Document, body: &HtmlElement, window: &Windo // Setup resize handler let canvas_clone = canvas.clone(); - let system_resize = particle_system.clone(); - let window_clone = window.clone(); + let system_resize = wave_system.clone(); + let window_resize = window.clone(); let resize_closure = Closure::wrap(Box::new(move || { - let new_width = window_clone.inner_width().unwrap().as_f64().unwrap_or(800.0); - let new_height = window_clone.inner_height().unwrap().as_f64().unwrap_or(600.0); + let new_width = window_resize.inner_width().unwrap().as_f64().unwrap_or(800.0); + let new_height = window_resize.inner_height().unwrap().as_f64().unwrap_or(600.0); canvas_clone.set_width(new_width as u32); canvas_clone.set_height(new_height as u32);