Skip to content

fix(inspector): mirror x/y/w/h on text nodes#34

Merged
chiefcll merged 1 commit into
mainfrom
fix/inspector-text-node-position
May 23, 2026
Merged

fix(inspector): mirror x/y/w/h on text nodes#34
chiefcll merged 1 commit into
mainfrom
fix/inspector-text-node-position

Conversation

@chiefcll
Copy link
Copy Markdown
Contributor

Summary

Two compounding bugs caused the Inspector's mirror <div> for CoreTextNode instances to ignore layout/transform updates. Setting textNode.x = 100 (or y, w, h, mountX, etc.) updated the canvas correctly but the DOM mirror stayed at its parent's origin, making the Inspector visually misleading for any app that uses text.

What was broken

Bug 1 — proxy walked only one level of the prototype chain.
createProxy looked up property descriptors with Object.getOwnPropertyDescriptor(node, …) then a single Object.getPrototypeOf(node) step. x / y / w / h / mountX / mountY / alpha / rotation / scale / color / clipping / zIndex are defined on CoreNode.prototype, which is two hops up from a CoreTextNode instance (since CoreTextNode extends CoreNode). The lookup returned undefined and the proxy returned early — no trap was installed for those properties on text nodes, so updates never reached the mirror div.

Bug 2 — createTextNode passed the wrong prop bag.
createDiv was called with node.textProps only (text/font/lineHeight/etc.). That bag has no x/y/w/h/mount*, so the mirror div's initial paint had no left/top and rendered at the parent's origin regardless of where the canvas drew the text.

Regular (non-text) CoreNode instances were unaffected because their prototype is CoreNode.prototype directly, and createNode already passes node.props.

Fix

  • Walk the full prototype chain in createProxy until the descriptor is found or null is reached.
  • Merge node.props and node.textProps in createTextNode so layout fields land in the initial createDiv call.

Test plan

  • Open an example with the inspector enabled and a text node; confirm the mirror div starts at the same on-screen position as the canvas text.
  • Mutate textNode.x, textNode.y, textNode.w, textNode.h at runtime; mirror div tracks.
  • Set mountX: 0.5 / mountY: 0.5 on a text node; mount-offset math runs (updateNodeProperty branch at the bottom of the file).
  • Regular (non-text) nodes still work — prototype walk is a superset of the old single-level lookup.
  • pnpm build clean (verified locally).

Notes for the reviewer

  • Latent edge case (not addressed here): if mountX/Y is set on a text node before the text has loaded, props.w/props.h are still undefined and the mount-offset math computes NaN. Pre-existing; worth a follow-up but out of scope for this fix.
  • This bug has likely been silent since CoreTextNode was introduced — anyone using the Inspector to debug text positioning was getting incorrect mirror positions.

🤖 Generated with Claude Code

Two compounding bugs caused Inspector mirror divs for CoreTextNode to
ignore layout/transform updates.

1. createProxy only walked one level up the prototype chain when looking
   up property descriptors. x/y/w/h/mountX/mountY/alpha/rotation/scale/
   color/clipping/zIndex are defined on CoreNode.prototype, which is two
   hops up from a CoreTextNode instance. The descriptor lookup returned
   undefined and the proxy skipped installing traps for those props
   entirely — so assigning `textNode.x = 100` updated the canvas but
   never touched the mirror div. Now walks the full prototype chain.

2. createTextNode passed only `node.textProps` (text/font/lineHeight/
   etc.) to createDiv. That bag has no x/y/w/h/mount*, so the mirror
   div's initial paint had no left/top and rendered at the parent's
   origin regardless of where the canvas drew the text. Now merges
   node.props and node.textProps so layout fields land in the first
   paint.

Regular (non-text) nodes are unaffected — the prototype walk is a
superset of the old single-level lookup, and createNode already passed
the correct prop bag.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@chiefcll chiefcll merged commit 8abd3d8 into main May 23, 2026
1 check passed
@chiefcll chiefcll deleted the fix/inspector-text-node-position branch May 23, 2026 20:55
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant