some glitchyness with iframes, check the iframe header #16

Closed
opened 2026-04-20 15:19:36 +00:00 by mahmoud · 4 comments
Owner
No description provided.
Member

Implementation Spec for Issue #16

Objective

Eliminate the visual desync between the Konva-rendered webframe header/body and the HTML iframe overlay during drag, stage pan, and wheel-zoom by hiding the overlay during these interactions and restoring it when they end.

Requirements

  • During webframe drag, stage drag (pan), and wheel-zoom, the HTML overlay wrapper must be hidden (display:none) so only the Konva-rendered group (bg, header, label, placeholder) is visible while moving.
  • When the interaction ends (dragend, wheel debounce timeout), the overlay must be re-positioned and shown again (display:block) in one atomic step.
  • The existing setAllInteractive(pointer-events) behavior invoked by transformer and layer drag handlers in tools.js must remain in place (needed for transformer over iframes).
  • The Konva .placeholder Text and .label Text must be kept in sync with the current bg width/height after a resize, so the visible placeholder during drag/pan/zoom matches the real frame dimensions.
  • The overlay's displayed size must continue to match bg's current dimensions (already handled by updateOverlayPosition reading from .bg).

Files to Modify

  • crates/hero_whiteboard_ui/static/web/js/whiteboard/webframe.js - add hideOverlay(id) / showOverlay(id) helpers; hook them into group dragstart/dragend, stage dragstart/dragend, stage wheel (with debounce), and expose hideAllOverlays() / showAllOverlays() for the transformer path in tools.js.
  • crates/hero_whiteboard_ui/static/web/js/whiteboard/tools.js - on transformstart hide all webframe overlays (in addition to disabling pointer events); on transformend show them again after applyTransform has updated dimensions.
  • crates/hero_whiteboard_ui/static/web/js/whiteboard/objects.js - in the webframe branch of applyTransform, also update the .label and .placeholder Text nodes' width so they match the new bg dimensions.

Implementation Plan

Step 1: Add overlay hide/show helpers in webframe.js

Files: crates/hero_whiteboard_ui/static/web/js/whiteboard/webframe.js

  • Add hideOverlay(id) that sets wrapper.style.display = 'none' and marks overlays[id]._hiddenForInteraction = true.
  • Add showOverlay(id, group) that clears the _hiddenForInteraction flag and calls updateOverlayPosition(id, group).
  • Modify updateOverlayPosition so that if overlay._hiddenForInteraction is true it updates left/top/width/height silently but does NOT set display = 'block'.
  • Add module-level helpers hideAllOverlays() and showAllOverlays() and export them.

Dependencies: none

Step 2: Hide/show on group drag in webframe.js

Files: crates/hero_whiteboard_ui/static/web/js/whiteboard/webframe.js

  • Extend the dragstart handler to call hideOverlay(id).
  • Remove the per-frame updateOverlayPosition from the dragmove handler.
  • Call showOverlay(id, group) on dragend.

Dependencies: Step 1

Step 3: Hide/show on stage pan in webframe.js

Files: crates/hero_whiteboard_ui/static/web/js/whiteboard/webframe.js

  • Replace the stage.on('dragmove.wf_<id>') listener with stage.on('dragstart.wf_<id>') (hide) and stage.on('dragend.wf_<id>') (show).
  • Update remapOverlay and destroyOverlay to detach the new namespaced listeners.

Dependencies: Step 1

Step 4: Hide/show on wheel zoom in webframe.js

Files: crates/hero_whiteboard_ui/static/web/js/whiteboard/webframe.js

  • Replace the wheel.wf_<id> setTimeout-based handler with a debounced hide-then-show handler (~150 ms debounce).
  • Store the pending timer on overlays[id]._wheelTimeout and cancel it on destroy/remap.

Dependencies: Step 1

Step 5: Hide overlays during transform in tools.js

Files: crates/hero_whiteboard_ui/static/web/js/whiteboard/tools.js

  • In transformer.on('transformstart'), after setAllInteractive(false), also call WhiteboardWebframe.hideAllOverlays().
  • In transformer.on('transformend'), after applyTransform(node) runs for each node and setAllInteractive(true), call WhiteboardWebframe.showAllOverlays().

Dependencies: Steps 1, 2

Step 6: Keep placeholder and label width in sync after resize in objects.js

Files: crates/hero_whiteboard_ui/static/web/js/whiteboard/objects.js

  • In the webframe branch of applyTransform, after updating bg/header widths, update .placeholder width/height and .label width to match the new bg dimensions.

Dependencies: none

Acceptance Criteria

  • Dragging a Web Frame shows the Konva group moving as one; the HTML iframe is not visible during the drag and re-appears only on dragend, exactly on top of the Konva bg.
  • Panning the stage: overlay hides on pan start and re-appears correctly positioned on pan end.
  • Wheel-zooming: overlay hides immediately, stays hidden until ~150 ms after the last wheel event, then re-appears sized and positioned to match the current zoom.
  • Resizing a Web Frame via the transformer: overlay is hidden during transform and re-appears matching the new bg dimensions; header, label, and placeholder Konva nodes all match the new width/height.
  • Transformer can still drag/resize a Web Frame even when the cursor passes over another iframe area.
  • Deleting or remapping a Web Frame cleanly removes all namespaced listeners and cancels any pending wheel-debounce timer.
  • No regression in the double-click-to-change-URL flow, undo/redo snapshots, or multi-user sync.

Notes

  • The core insight is that during active motion there is no way to make an HTML overlay and a Konva canvas paint in the same frame; hiding the overlay and relying on the Konva placeholder removes the race without rAF-based synchronization.
  • Step 6 is a pre-existing minor bug grouped into this fix because it shares the symptom surface.
## Implementation Spec for Issue #16 ### Objective Eliminate the visual desync between the Konva-rendered webframe header/body and the HTML iframe overlay during drag, stage pan, and wheel-zoom by hiding the overlay during these interactions and restoring it when they end. ### Requirements - During webframe drag, stage drag (pan), and wheel-zoom, the HTML overlay `wrapper` must be hidden (`display:none`) so only the Konva-rendered group (bg, header, label, placeholder) is visible while moving. - When the interaction ends (dragend, wheel debounce timeout), the overlay must be re-positioned and shown again (`display:block`) in one atomic step. - The existing `setAllInteractive(pointer-events)` behavior invoked by transformer and layer drag handlers in `tools.js` must remain in place (needed for transformer over iframes). - The Konva `.placeholder` Text and `.label` Text must be kept in sync with the current `bg` width/height after a resize, so the visible placeholder during drag/pan/zoom matches the real frame dimensions. - The overlay's displayed size must continue to match `bg`'s current dimensions (already handled by `updateOverlayPosition` reading from `.bg`). ### Files to Modify - `crates/hero_whiteboard_ui/static/web/js/whiteboard/webframe.js` - add `hideOverlay(id)` / `showOverlay(id)` helpers; hook them into group dragstart/dragend, stage dragstart/dragend, stage wheel (with debounce), and expose `hideAllOverlays()` / `showAllOverlays()` for the transformer path in tools.js. - `crates/hero_whiteboard_ui/static/web/js/whiteboard/tools.js` - on transformstart hide all webframe overlays (in addition to disabling pointer events); on transformend show them again after `applyTransform` has updated dimensions. - `crates/hero_whiteboard_ui/static/web/js/whiteboard/objects.js` - in the `webframe` branch of `applyTransform`, also update the `.label` and `.placeholder` Text nodes' `width` so they match the new bg dimensions. ### Implementation Plan #### Step 1: Add overlay hide/show helpers in webframe.js Files: `crates/hero_whiteboard_ui/static/web/js/whiteboard/webframe.js` - Add `hideOverlay(id)` that sets `wrapper.style.display = 'none'` and marks `overlays[id]._hiddenForInteraction = true`. - Add `showOverlay(id, group)` that clears the `_hiddenForInteraction` flag and calls `updateOverlayPosition(id, group)`. - Modify `updateOverlayPosition` so that if `overlay._hiddenForInteraction` is true it updates left/top/width/height silently but does NOT set `display = 'block'`. - Add module-level helpers `hideAllOverlays()` and `showAllOverlays()` and export them. Dependencies: none #### Step 2: Hide/show on group drag in webframe.js Files: `crates/hero_whiteboard_ui/static/web/js/whiteboard/webframe.js` - Extend the `dragstart` handler to call `hideOverlay(id)`. - Remove the per-frame `updateOverlayPosition` from the `dragmove` handler. - Call `showOverlay(id, group)` on `dragend`. Dependencies: Step 1 #### Step 3: Hide/show on stage pan in webframe.js Files: `crates/hero_whiteboard_ui/static/web/js/whiteboard/webframe.js` - Replace the `stage.on('dragmove.wf_<id>')` listener with `stage.on('dragstart.wf_<id>')` (hide) and `stage.on('dragend.wf_<id>')` (show). - Update `remapOverlay` and `destroyOverlay` to detach the new namespaced listeners. Dependencies: Step 1 #### Step 4: Hide/show on wheel zoom in webframe.js Files: `crates/hero_whiteboard_ui/static/web/js/whiteboard/webframe.js` - Replace the `wheel.wf_<id>` setTimeout-based handler with a debounced hide-then-show handler (~150 ms debounce). - Store the pending timer on `overlays[id]._wheelTimeout` and cancel it on destroy/remap. Dependencies: Step 1 #### Step 5: Hide overlays during transform in tools.js Files: `crates/hero_whiteboard_ui/static/web/js/whiteboard/tools.js` - In `transformer.on('transformstart')`, after `setAllInteractive(false)`, also call `WhiteboardWebframe.hideAllOverlays()`. - In `transformer.on('transformend')`, after `applyTransform(node)` runs for each node and `setAllInteractive(true)`, call `WhiteboardWebframe.showAllOverlays()`. Dependencies: Steps 1, 2 #### Step 6: Keep placeholder and label width in sync after resize in objects.js Files: `crates/hero_whiteboard_ui/static/web/js/whiteboard/objects.js` - In the `webframe` branch of `applyTransform`, after updating bg/header widths, update `.placeholder` width/height and `.label` width to match the new bg dimensions. Dependencies: none ### Acceptance Criteria - [ ] Dragging a Web Frame shows the Konva group moving as one; the HTML iframe is not visible during the drag and re-appears only on dragend, exactly on top of the Konva bg. - [ ] Panning the stage: overlay hides on pan start and re-appears correctly positioned on pan end. - [ ] Wheel-zooming: overlay hides immediately, stays hidden until ~150 ms after the last wheel event, then re-appears sized and positioned to match the current zoom. - [ ] Resizing a Web Frame via the transformer: overlay is hidden during transform and re-appears matching the new bg dimensions; header, label, and placeholder Konva nodes all match the new width/height. - [ ] Transformer can still drag/resize a Web Frame even when the cursor passes over another iframe area. - [ ] Deleting or remapping a Web Frame cleanly removes all namespaced listeners and cancels any pending wheel-debounce timer. - [ ] No regression in the double-click-to-change-URL flow, undo/redo snapshots, or multi-user sync. ### Notes - The core insight is that during active motion there is no way to make an HTML overlay and a Konva canvas paint in the same frame; hiding the overlay and relying on the Konva placeholder removes the race without rAF-based synchronization. - Step 6 is a pre-existing minor bug grouped into this fix because it shares the symptom surface.
Member

Test Results

  • cargo check --workspace: pass
  • cargo clippy -- -D warnings: pass
  • cargo fmt --check: pass
  • cargo test --workspace --lib: 0 passed / 0 failed (0)

Note: changes are in vanilla JS (frontend) and have no corresponding Rust tests. UI behavior must be verified manually in the browser.

## Test Results - `cargo check --workspace`: pass - `cargo clippy -- -D warnings`: pass - `cargo fmt --check`: pass - `cargo test --workspace --lib`: 0 passed / 0 failed (0) Note: changes are in vanilla JS (frontend) and have no corresponding Rust tests. UI behavior must be verified manually in the browser.
Member

Implementation Summary

All six steps from the approved spec are implemented.

Changes

crates/hero_whiteboard_ui/static/web/js/whiteboard/webframe.js

  • Added hideOverlay(id) / showOverlay(id, group) helpers plus module-level hideAllOverlays() / showAllOverlays().
  • Added an _hiddenForInteraction gate in updateOverlayPosition: while the flag is set, position/size are still updated but the wrapper's display stays none.
  • Replaced the per-frame group.on('dragmove', updateOverlayPosition) with dragstarthideOverlay and dragendshowOverlay.
  • Replaced the per-frame stage.on('dragmove.wf_<id>', …) pan listener with dragstart.wf_<id> / dragend.wf_<id>.
  • Replaced the setTimeout(…, 10) wheel handler with a 150 ms debounced hide-then-show using _wheelTimeout.
  • destroyOverlay and remapOverlay now clear pending _wheelTimeout and detach the new dragstart.wf_<id> / dragend.wf_<id> namespaced listeners.
  • Exposed the new helpers from the IIFE.

crates/hero_whiteboard_ui/static/web/js/whiteboard/tools.js

  • transformer.on('transformstart', …) now also calls WhiteboardWebframe.hideAllOverlays() after setAllInteractive(false).
  • transformer.on('transformend', …) calls WhiteboardWebframe.showAllOverlays() after applyTransform has written final bg dimensions (overlay picks up new size correctly).

crates/hero_whiteboard_ui/static/web/js/whiteboard/objects.js

  • applyTransform webframe branch now also updates the .placeholder Text (width + height) and .label Text (width) to match the new bg dimensions, so the Konva stand-in shown during drag/pan/zoom always matches the real frame.

Test Results

  • cargo check --workspace: pass
  • cargo clippy --workspace -- -D warnings: pass
  • cargo fmt --check: pass
  • cargo test --workspace --lib: 0 passed / 0 failed (0 total)

The workspace does not currently have Rust unit tests that exercise this code path. The changes are entirely in vanilla JS (frontend); UI behavior needs to be verified manually in the browser.

Manual verification checklist

  • Drag a Web Frame across the board: the iframe body hides on drag start and re-appears correctly positioned on drag end; header and body never look detached.
  • Pan the stage with a Web Frame visible: overlay hides on pan start and re-appears on pan end.
  • Wheel-zoom while a Web Frame is visible: overlay hides immediately, returns ~150 ms after the last wheel event at the correct position/size.
  • Resize via the transformer: overlay stays hidden throughout the resize and reappears sized to the new bg dimensions; the header, label, and placeholder all stay in sync with the new width/height.
  • Transformer can still resize a Web Frame when the cursor crosses into an iframe area (existing setAllInteractive(false) path is preserved).
  • Double-click-to-change-URL, undo/redo, and multi-user sync still work.
## Implementation Summary All six steps from the approved spec are implemented. ### Changes **`crates/hero_whiteboard_ui/static/web/js/whiteboard/webframe.js`** - Added `hideOverlay(id)` / `showOverlay(id, group)` helpers plus module-level `hideAllOverlays()` / `showAllOverlays()`. - Added an `_hiddenForInteraction` gate in `updateOverlayPosition`: while the flag is set, position/size are still updated but the wrapper's `display` stays `none`. - Replaced the per-frame `group.on('dragmove', updateOverlayPosition)` with `dragstart` → `hideOverlay` and `dragend` → `showOverlay`. - Replaced the per-frame `stage.on('dragmove.wf_<id>', …)` pan listener with `dragstart.wf_<id>` / `dragend.wf_<id>`. - Replaced the `setTimeout(…, 10)` wheel handler with a 150 ms debounced hide-then-show using `_wheelTimeout`. - `destroyOverlay` and `remapOverlay` now clear pending `_wheelTimeout` and detach the new `dragstart.wf_<id>` / `dragend.wf_<id>` namespaced listeners. - Exposed the new helpers from the IIFE. **`crates/hero_whiteboard_ui/static/web/js/whiteboard/tools.js`** - `transformer.on('transformstart', …)` now also calls `WhiteboardWebframe.hideAllOverlays()` after `setAllInteractive(false)`. - `transformer.on('transformend', …)` calls `WhiteboardWebframe.showAllOverlays()` after `applyTransform` has written final bg dimensions (overlay picks up new size correctly). **`crates/hero_whiteboard_ui/static/web/js/whiteboard/objects.js`** - `applyTransform` webframe branch now also updates the `.placeholder` Text (width + height) and `.label` Text (width) to match the new bg dimensions, so the Konva stand-in shown during drag/pan/zoom always matches the real frame. ### Test Results - `cargo check --workspace`: pass - `cargo clippy --workspace -- -D warnings`: pass - `cargo fmt --check`: pass - `cargo test --workspace --lib`: 0 passed / 0 failed (0 total) The workspace does not currently have Rust unit tests that exercise this code path. The changes are entirely in vanilla JS (frontend); UI behavior needs to be verified manually in the browser. ### Manual verification checklist - Drag a Web Frame across the board: the iframe body hides on drag start and re-appears correctly positioned on drag end; header and body never look detached. - Pan the stage with a Web Frame visible: overlay hides on pan start and re-appears on pan end. - Wheel-zoom while a Web Frame is visible: overlay hides immediately, returns ~150 ms after the last wheel event at the correct position/size. - Resize via the transformer: overlay stays hidden throughout the resize and reappears sized to the new bg dimensions; the header, label, and placeholder all stay in sync with the new width/height. - Transformer can still resize a Web Frame when the cursor crosses into an iframe area (existing `setAllInteractive(false)` path is preserved). - Double-click-to-change-URL, undo/redo, and multi-user sync still work.
Member

Pull request opened: #23

This PR implements the changes discussed in this issue.

Pull request opened: https://forge.ourworld.tf/lhumina_code/hero_whiteboard/pulls/23 This PR implements the changes discussed in this issue.
Sign in to join this conversation.
No milestone
No project
No assignees
2 participants
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
lhumina_code/hero_whiteboard#16
No description provided.