beauty, but not for demo...
This commit is contained in:
parent
a81ec7901d
commit
db593cd299
|
|
@ -237,11 +237,11 @@ export function main() {
|
||||||
wasm.main();
|
wasm.main();
|
||||||
}
|
}
|
||||||
|
|
||||||
function __wbg_adapter_4(arg0, arg1) {
|
function __wbg_adapter_8(arg0, arg1) {
|
||||||
wasm.__wbindgen_export_4(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));
|
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));
|
const ret = getObject(arg0).appendChild(getObject(arg1));
|
||||||
return addHeapObject(ret);
|
return addHeapObject(ret);
|
||||||
}, arguments) };
|
}, 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) {
|
imports.wbg.__wbg_beginPath_119487ebd04e9e1c = function(arg0) {
|
||||||
getObject(arg0).beginPath();
|
getObject(arg0).beginPath();
|
||||||
};
|
};
|
||||||
|
|
@ -314,14 +311,17 @@ function __wbg_get_imports() {
|
||||||
const ret = getObject(arg0).classList;
|
const ret = getObject(arg0).classList;
|
||||||
return addHeapObject(ret);
|
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) {
|
imports.wbg.__wbg_createElement_4909dfa2011f2abe = function() { return handleError(function (arg0, arg1, arg2) {
|
||||||
const ret = getObject(arg0).createElement(getStringFromWasm0(arg1, arg2));
|
const ret = getObject(arg0).createElement(getStringFromWasm0(arg1, arg2));
|
||||||
return addHeapObject(ret);
|
return addHeapObject(ret);
|
||||||
}, arguments) };
|
}, arguments) };
|
||||||
imports.wbg.__wbg_createRadialGradient_b10566e092cb7089 = function() { return handleError(function (arg0, arg1, arg2, arg3, arg4, arg5, arg6) {
|
imports.wbg.__wbg_createLinearGradient_098463fca2d0190f = function(arg0, arg1, arg2, arg3, arg4) {
|
||||||
const ret = getObject(arg0).createRadialGradient(arg1, arg2, arg3, arg4, arg5, arg6);
|
const ret = getObject(arg0).createLinearGradient(arg1, arg2, arg3, arg4);
|
||||||
return addHeapObject(ret);
|
return addHeapObject(ret);
|
||||||
}, arguments) };
|
};
|
||||||
imports.wbg.__wbg_document_7d29d139bd619045 = function(arg0) {
|
imports.wbg.__wbg_document_7d29d139bd619045 = function(arg0) {
|
||||||
const ret = getObject(arg0).document;
|
const ret = getObject(arg0).document;
|
||||||
return isLikeNone(ret) ? 0 : addHeapObject(ret);
|
return isLikeNone(ret) ? 0 : addHeapObject(ret);
|
||||||
|
|
@ -421,9 +421,15 @@ function __wbg_get_imports() {
|
||||||
const ret = getObject(arg0).length;
|
const ret = getObject(arg0).length;
|
||||||
return ret;
|
return ret;
|
||||||
};
|
};
|
||||||
|
imports.wbg.__wbg_lineTo_d9b895383c2303ba = function(arg0, arg1, arg2) {
|
||||||
|
getObject(arg0).lineTo(arg1, arg2);
|
||||||
|
};
|
||||||
imports.wbg.__wbg_log_6c7b5f4f00b8ce3f = function(arg0) {
|
imports.wbg.__wbg_log_6c7b5f4f00b8ce3f = function(arg0) {
|
||||||
console.log(getObject(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() {
|
imports.wbg.__wbg_new_19c25a3f2fa63a02 = function() {
|
||||||
const ret = new Object();
|
const ret = new Object();
|
||||||
return addHeapObject(ret);
|
return addHeapObject(ret);
|
||||||
|
|
@ -443,10 +449,6 @@ function __wbg_get_imports() {
|
||||||
const ret = getObject(arg0).querySelectorAll(getStringFromWasm0(arg1, arg2));
|
const ret = getObject(arg0).querySelectorAll(getStringFromWasm0(arg1, arg2));
|
||||||
return addHeapObject(ret);
|
return addHeapObject(ret);
|
||||||
}, arguments) };
|
}, arguments) };
|
||||||
imports.wbg.__wbg_random_7ed63a0b38ee3b75 = function() {
|
|
||||||
const ret = Math.random();
|
|
||||||
return ret;
|
|
||||||
};
|
|
||||||
imports.wbg.__wbg_requestAnimationFrame_ddc84a7def436784 = function() { return handleError(function (arg0, arg1) {
|
imports.wbg.__wbg_requestAnimationFrame_ddc84a7def436784 = function() { return handleError(function (arg0, arg1) {
|
||||||
const ret = getObject(arg0).requestAnimationFrame(getObject(arg1));
|
const ret = getObject(arg0).requestAnimationFrame(getObject(arg1));
|
||||||
return ret;
|
return ret;
|
||||||
|
|
@ -540,7 +542,7 @@ function __wbg_get_imports() {
|
||||||
};
|
};
|
||||||
imports.wbg.__wbindgen_cast_aaa93aae03c115ab = function(arg0, arg1) {
|
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`.
|
// 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);
|
return addHeapObject(ret);
|
||||||
};
|
};
|
||||||
imports.wbg.__wbindgen_cast_d6cd19b81560fd6e = function(arg0) {
|
imports.wbg.__wbindgen_cast_d6cd19b81560fd6e = function(arg0) {
|
||||||
|
|
@ -550,7 +552,7 @@ function __wbg_get_imports() {
|
||||||
};
|
};
|
||||||
imports.wbg.__wbindgen_cast_e58c2e3d55f4d158 = function(arg0, arg1) {
|
imports.wbg.__wbindgen_cast_e58c2e3d55f4d158 = function(arg0, arg1) {
|
||||||
// Cast intrinsic for `Closure(Closure { dtor_idx: 1, function: Function { arguments: [NamedExternref("Array<any>"), NamedExternref("IntersectionObserver")], shim_idx: 4, ret: Unit, inner_ret: Some(Unit) }, mutable: true }) -> Externref`.
|
// Cast intrinsic for `Closure(Closure { dtor_idx: 1, function: Function { arguments: [NamedExternref("Array<any>"), 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);
|
return addHeapObject(ret);
|
||||||
};
|
};
|
||||||
imports.wbg.__wbindgen_object_clone_ref = function(arg0) {
|
imports.wbg.__wbindgen_object_clone_ref = function(arg0) {
|
||||||
|
|
|
||||||
Binary file not shown.
308
src/lib.rs
308
src/lib.rs
|
|
@ -8,180 +8,141 @@ use web_sys::{
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
// Particle structure
|
// Wave layer for fluid simulation
|
||||||
struct Particle {
|
struct WaveLayer {
|
||||||
x: f64,
|
amplitude: f64,
|
||||||
y: f64,
|
frequency: f64,
|
||||||
vx: f64,
|
speed: f64,
|
||||||
vy: f64,
|
offset: f64,
|
||||||
size: f64,
|
|
||||||
life: f64,
|
|
||||||
max_life: f64,
|
|
||||||
hue: f64,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Particle {
|
// Fluid wave system
|
||||||
fn new(x: f64, y: f64, hue: f64) -> Self {
|
struct FluidWaves {
|
||||||
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<Particle>,
|
|
||||||
width: f64,
|
width: f64,
|
||||||
height: f64,
|
height: f64,
|
||||||
max_particles: usize,
|
|
||||||
time: f64,
|
time: f64,
|
||||||
|
layers: Vec<WaveLayer>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ParticleSystem {
|
impl FluidWaves {
|
||||||
fn new(width: f64, height: f64) -> Self {
|
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 {
|
Self {
|
||||||
particles: Vec::new(),
|
|
||||||
width,
|
width,
|
||||||
height,
|
height,
|
||||||
max_particles: 1200,
|
|
||||||
time: 0.0,
|
time: 0.0,
|
||||||
}
|
layers,
|
||||||
}
|
|
||||||
|
|
||||||
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));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update(&mut self) {
|
fn update(&mut self) {
|
||||||
self.time += 1.0;
|
self.time += 1.0;
|
||||||
|
}
|
||||||
|
|
||||||
// Update existing particles
|
// Calculate wave height at a given position with randomness
|
||||||
for particle in &mut self.particles {
|
fn wave_height(&self, x: f64, y: f64, randomness: f64) -> f64 {
|
||||||
particle.update(self.width, self.height, self.time);
|
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
|
height
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn draw(&self, ctx: &CanvasRenderingContext2d) {
|
fn draw(&self, ctx: &CanvasRenderingContext2d) {
|
||||||
for particle in &self.particles {
|
// Draw smooth gradient waves at the bottom
|
||||||
particle.draw(ctx);
|
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()
|
.unwrap()
|
||||||
.dyn_into::<CanvasRenderingContext2d>()?;
|
.dyn_into::<CanvasRenderingContext2d>()?;
|
||||||
|
|
||||||
// Initialize particle system
|
// Initialize fluid wave system
|
||||||
let particle_system = Rc::new(RefCell::new(ParticleSystem::new(width, height)));
|
let wave_system = Rc::new(RefCell::new(FluidWaves::new(width, height)));
|
||||||
|
console::log_1(&"🌊 Fluid wave system initialized!".into());
|
||||||
// Spawn initial particles
|
|
||||||
particle_system.borrow_mut().spawn_particles(600);
|
|
||||||
console::log_1(&format!("🌟 Spawned {} initial particles", particle_system.borrow().particles.len()).into());
|
|
||||||
|
|
||||||
// Setup animation loop
|
// Setup animation loop
|
||||||
let system_clone = particle_system.clone();
|
let system_clone = wave_system.clone();
|
||||||
let context_clone = context.clone();
|
let context_clone = context.clone();
|
||||||
let frame_count = Rc::new(RefCell::new(0u32));
|
|
||||||
let window_clone = window.clone();
|
let window_clone = window.clone();
|
||||||
|
|
||||||
let animate_closure = Rc::new(RefCell::new(None::<Closure<dyn FnMut()>>));
|
let animate_closure = Rc::new(RefCell::new(None::<Closure<dyn FnMut()>>));
|
||||||
let animate_clone = animate_closure.clone();
|
let animate_clone = animate_closure.clone();
|
||||||
let frame_clone = frame_count.clone();
|
|
||||||
|
|
||||||
*animate_closure.borrow_mut() = Some(Closure::wrap(Box::new(move || {
|
*animate_closure.borrow_mut() = Some(Closure::wrap(Box::new(move || {
|
||||||
*frame_clone.borrow_mut() += 1;
|
// Clear canvas
|
||||||
|
context_clone.set_fill_style_str("rgba(10, 14, 23, 1.0)");
|
||||||
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);
|
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_mut().update();
|
||||||
system_clone.borrow().draw(&context_clone);
|
system_clone.borrow().draw(&context_clone);
|
||||||
|
|
||||||
|
|
@ -299,12 +237,12 @@ fn setup_particle_canvas(document: &Document, body: &HtmlElement, window: &Windo
|
||||||
|
|
||||||
// Setup resize handler
|
// Setup resize handler
|
||||||
let canvas_clone = canvas.clone();
|
let canvas_clone = canvas.clone();
|
||||||
let system_resize = particle_system.clone();
|
let system_resize = wave_system.clone();
|
||||||
let window_clone = window.clone();
|
let window_resize = window.clone();
|
||||||
|
|
||||||
let resize_closure = Closure::wrap(Box::new(move || {
|
let resize_closure = Closure::wrap(Box::new(move || {
|
||||||
let new_width = window_clone.inner_width().unwrap().as_f64().unwrap_or(800.0);
|
let new_width = window_resize.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_height = window_resize.inner_height().unwrap().as_f64().unwrap_or(600.0);
|
||||||
|
|
||||||
canvas_clone.set_width(new_width as u32);
|
canvas_clone.set_width(new_width as u32);
|
||||||
canvas_clone.set_height(new_height as u32);
|
canvas_clone.set_height(new_height as u32);
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue