Improve realtime collaboration feedback and previews#523
Conversation
| usePlacementPreview.getState().set( | ||
| node, | ||
| node.parentId ? (useScene.getState().nodes[node.parentId as AnyNodeId] ?? null) : null, | ||
| ) |
There was a problem hiding this comment.
Stale item placement ghost
High Severity
The useDraftNode hook initializes the usePlacementPreview store only when a draft node is created or adopted, but doesn't update it as the node's position changes in the scene. This causes UI components relying on usePlacementPreview to render a stale ghost of the item at its initial position, appearing alongside the correctly rendered live item.
Reviewed by Cursor Bugbot for commit 1ab9f92. Configure here.
| if (obj) outliner.hoveredObjects.push(obj) | ||
| } | ||
| }, [selection, hoveredId, outliner, nodes]) | ||
| }, [selection, externalSelectedIds, hoveredId, outliner, nodes, geometryRevision]) |
There was a problem hiding this comment.
Editor ignores remote highlights
High Severity
The externalSelectedIds are now included in the viewer's OutlinerSync for displaying selections, but the editor's EditorOutlinerSync and SelectionMaterialSync haven't been updated to also incorporate these IDs. This means collaborator selections aren't visible in the editor.
Reviewed by Cursor Bugbot for commit 1ab9f92. Configure here.
| if (live?.type !== 'door') return | ||
| draftRef.current = live | ||
| publishPlacementPreview(live, parentNode) | ||
| } |
There was a problem hiding this comment.
Opening draft ghosts duplicate
Medium Severity
On-wall door/window drafts are already scene nodes rendered by the floorplan registry, and publishDraftPreview also pushes that same live node into usePlacementPreview. Split 2D+3D placement stacks two identical opening symbols and darkens the ghost via overlapping opacity.
Additional Locations (2)
Reviewed by Cursor Bugbot for commit 1ab9f92. Configure here.
1ab9f92 to
5444022
Compare
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes using high effort and found 1 potential issue.
There are 4 total unresolved issues (including 3 from previous reviews).
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 5444022. Configure here.
| // Howler queues per-play mutations while a sound is loading. If its global | ||
| // AudioContext is replaced before that queue drains, stereo setup can try | ||
| // to connect nodes from different contexts and throw asynchronously. | ||
| if (sound.state() !== 'loaded') return |
There was a problem hiding this comment.
SFX debounce blocks retries
High Severity
The lastPlayedAt timestamp is recorded before verifying the sound asset is loaded. If the sound isn't ready, the SFX is skipped, but the debounce window is still consumed. This incorrectly prevents the SFX from playing for minIntervalMs, even after the asset becomes available.
Reviewed by Cursor Bugbot for commit 5444022. Configure here.
5444022 to
e1a4dba
Compare


Summary
Verification
bun run check-typesbun run buildNote
Medium Risk
Touches placement lifecycles across many node tools and shared viewer selection/outliner paths; regressions could show stale ghosts or wrong highlights, though SFX and preview changes are largely additive with tests.
Overview
Improves realtime collaboration feedback and placement preview parity between 2D floor plan and 3D.
Remote selection — The viewer gains
externalSelectedIds/setExternalSelectedIdsso a host can drive outliner selection highlights without mutating the user’s editableselection. Outliner sync also reacts togeometryRevisionso highlights stay aligned after mesh updates.Unified placement preview — Tools and draft-item flows publish transient nodes into
usePlacementPreview.FloorplanNodePreviewnow builds floorplan geometry with siblings, level data, theme palette, and optional interaction flags so 2D ghosts match committed symbols. Door/window tools publish previews for on-wall drafts and off-host floating ghosts (synthetic host wall); roof accessories (chimney, dormer, skylight, solar panel) and item drafts wire the same store with explicit clear on commit/cancel.Registry tooling — Kinds register lazy
previewmodules (including wall segment extrusion preview and catalogItemPreview).preloadRegistryToolModulespreloads tool, preview, renderer, system, and move modules before the lazy tool mounts so first placement stays synchronous under dev bundling.Audio —
playSFXacceptssource,stereo, andvolumeMultiplierfor quieter, spatial remote cues; rate limiting is per source, remote yields to recent local plays, and playback is skipped while Howler sounds are still loading to avoid async Web Audio errors.Reviewed by Cursor Bugbot for commit e1a4dba. Bugbot is set up for automated code reviews on this repo. Configure here.