fix: multiple bugs

* Hard-refresh saves coords before disconnect
* Position persisted between sessions
* Scaling isn't assumed on initial, it waits for calculations to finish
This commit is contained in:
Evan Carroll 2026-01-13 23:42:22 -06:00
parent a96581cbf0
commit 98f38c9714
3 changed files with 99 additions and 8 deletions

View file

@ -97,6 +97,9 @@ pub fn RealmSceneViewer(
let offset_x = StoredValue::new(0.0_f64);
let offset_y = StoredValue::new(0.0_f64);
// Signal to track when scale factors have been properly calculated
let (scales_ready, set_scales_ready) = signal(false);
// Handle canvas click for movement or prop pickup (on avatar canvas - topmost layer)
#[cfg(feature = "hydrate")]
let on_canvas_click = {
@ -125,9 +128,9 @@ pub fn RealmSceneViewer(
let scene_x = scene_x.max(0.0).min(scene_width as f64);
let scene_y = scene_y.max(0.0).min(scene_height as f64);
// Check if click is within 32px of any loose prop
// Check if click is within 40px of any loose prop
let current_props = loose_props.get();
let prop_click_radius = 32.0;
let prop_click_radius = 40.0;
let mut clicked_prop: Option<Uuid> = None;
for prop in &current_props {
@ -220,6 +223,9 @@ pub fn RealmSceneViewer(
offset_x.set_value(draw_x);
offset_y.set_value(draw_y);
// Signal that scale factors are ready
set_scales_ready.set(true);
if let Ok(Some(ctx)) = canvas_el.get_context("2d") {
let ctx: web_sys::CanvasRenderingContext2d =
ctx.dyn_into::<web_sys::CanvasRenderingContext2d>().unwrap();
@ -271,6 +277,11 @@ pub fn RealmSceneViewer(
let current_members = members.get();
let current_bubbles = active_bubbles.get();
// Skip drawing if scale factors haven't been calculated yet
if !scales_ready.get() {
return;
}
let Some(canvas) = avatar_canvas_ref.get() else {
return;
};
@ -335,6 +346,11 @@ pub fn RealmSceneViewer(
// Track loose_props signal
let current_props = loose_props.get();
// Skip drawing if scale factors haven't been calculated yet
if !scales_ready.get() {
return;
}
let Some(canvas) = props_canvas_ref.get() else {
return;
};
@ -452,7 +468,7 @@ fn draw_avatars(
let x = member.member.position_x * scale_x + offset_x;
let y = member.member.position_y * scale_y + offset_y;
let avatar_size = 48.0 * scale_x.min(scale_y);
let avatar_size = 60.0 * scale_x.min(scale_y);
// Draw avatar placeholder circle
ctx.begin_path();
@ -544,7 +560,7 @@ fn draw_speech_bubbles(
current_time_ms: i64,
) {
let scale = scale_x.min(scale_y);
let avatar_size = 48.0 * scale;
let avatar_size = 60.0 * scale;
let max_bubble_width = 200.0 * scale;
let padding = 8.0 * scale;
let font_size = 12.0 * scale;
@ -704,7 +720,7 @@ fn draw_loose_props(
offset_x: f64,
offset_y: f64,
) {
let prop_size = 48.0 * scale_x.min(scale_y);
let prop_size = 60.0 * scale_x.min(scale_y);
for prop in props {
let x = prop.position_x * scale_x + offset_x;

View file

@ -61,6 +61,9 @@ pub fn RealmPage() -> impl IntoView {
// Loose props state
let (loose_props, set_loose_props) = signal(Vec::<LooseProp>::new());
// Track user's current position for saving on beforeunload
let (current_position, set_current_position) = signal((400.0_f64, 300.0_f64));
let realm_data = LocalResource::new(move || {
let slug = slug.get();
async move {
@ -233,6 +236,8 @@ pub fn RealmPage() -> impl IntoView {
// Handle position update via WebSocket
#[cfg(feature = "hydrate")]
let on_move = Callback::new(move |(x, y): (f64, f64)| {
// Track position for saving on beforeunload
set_current_position.set((x, y));
ws_sender.with_value(|sender| {
if let Some(send_fn) = sender {
send_fn(ClientMessage::UpdatePosition { x, y });
@ -359,6 +364,34 @@ pub fn RealmPage() -> impl IntoView {
// Store the closure for cleanup
*closure_holder_clone.borrow_mut() = Some(closure);
});
// Save position on page unload (beforeunload event)
Effect::new({
let ws_sender = ws_sender.clone();
move |_| {
let Some(window) = web_sys::window() else {
return;
};
let handler = Closure::<dyn Fn(web_sys::BeforeUnloadEvent)>::new({
let ws_sender = ws_sender.clone();
move |_: web_sys::BeforeUnloadEvent| {
let (x, y) = current_position.get_untracked();
ws_sender.with_value(|sender| {
if let Some(send_fn) = sender {
send_fn(ClientMessage::UpdatePosition { x, y });
}
});
}
});
let _ = window.add_event_listener_with_callback(
"beforeunload",
handler.as_ref().unchecked_ref(),
);
handler.forget();
}
});
}
// Callback for chat focus changes