From f188bbaea61f78f1bd50d9b929601cf40d764845 Mon Sep 17 00:00:00 2001 From: sambhram1 Date: Thu, 23 Oct 2025 11:34:36 +0530 Subject: [PATCH 1/3] "Fix: Large brush offset on iPad and high-DPI devices" --- frontend/src/io-managers/input.ts | 41 ++++++++++++++++++--- frontend/src/utility-functions/viewports.ts | 7 +++- 2 files changed, 41 insertions(+), 7 deletions(-) diff --git a/frontend/src/io-managers/input.ts b/frontend/src/io-managers/input.ts index 6da2dddcda..367830638c 100644 --- a/frontend/src/io-managers/input.ts +++ b/frontend/src/io-managers/input.ts @@ -38,6 +38,10 @@ export function createInputManager(editor: Editor, dialog: DialogState, portfoli let inPointerLock = false; const shakeSamples: { x: number; y: number; time: number }[] = []; let lastShakeTime = 0; + + // Get device pixel ratio for coordinate transformation + // This fixes the offset issue on high-DPI devices like iPad + const getDevicePixelRatio = () => window.devicePixelRatio || 1; // Event listeners @@ -160,9 +164,14 @@ export function createInputManager(editor: Editor, dialog: DialogState, portfoli const inGraphOverlay = get(document).graphViewOverlayOpen; if (!viewportPointerInteractionOngoing && (inFloatingMenu || inGraphOverlay)) return; + // Scale coordinates by device pixel ratio to fix offset on high-DPI devices like iPad + const dpr = getDevicePixelRatio(); + const scaledX = e.clientX * dpr; + const scaledY = e.clientY * dpr; + const modifiers = makeKeyboardModifiersBitfield(e); - if (detectShake(e)) editor.handle.onMouseShake(e.clientX, e.clientY, e.buttons, modifiers); - editor.handle.onMouseMove(e.clientX, e.clientY, e.buttons, modifiers); + if (detectShake(e)) editor.handle.onMouseShake(scaledX, scaledY, e.buttons, modifiers); + editor.handle.onMouseMove(scaledX, scaledY, e.buttons, modifiers); } function onPointerDown(e: PointerEvent) { @@ -190,8 +199,13 @@ export function createInputManager(editor: Editor, dialog: DialogState, portfoli } if (viewportPointerInteractionOngoing && isTargetingCanvas instanceof Element) { + // Scale coordinates by device pixel ratio to fix offset on high-DPI devices like iPad + const dpr = getDevicePixelRatio(); + const scaledX = e.clientX * dpr; + const scaledY = e.clientY * dpr; + const modifiers = makeKeyboardModifiersBitfield(e); - editor.handle.onMouseDown(e.clientX, e.clientY, e.buttons, modifiers); + editor.handle.onMouseDown(scaledX, scaledY, e.buttons, modifiers); } } @@ -208,8 +222,13 @@ export function createInputManager(editor: Editor, dialog: DialogState, portfoli if (textToolInteractiveInputElement) return; + // Scale coordinates by device pixel ratio to fix offset on high-DPI devices like iPad + const dpr = getDevicePixelRatio(); + const scaledX = e.clientX * dpr; + const scaledY = e.clientY * dpr; + const modifiers = makeKeyboardModifiersBitfield(e); - editor.handle.onMouseUp(e.clientX, e.clientY, e.buttons, modifiers); + editor.handle.onMouseUp(scaledX, scaledY, e.buttons, modifiers); } // Mouse events @@ -233,8 +252,13 @@ export function createInputManager(editor: Editor, dialog: DialogState, portfoli if (e.button === BUTTON_BACK) buttons = 8; // Back if (e.button === BUTTON_FORWARD) buttons = 16; // Forward + // Scale coordinates by device pixel ratio to fix offset on high-DPI devices like iPad + const dpr = getDevicePixelRatio(); + const scaledX = e.clientX * dpr; + const scaledY = e.clientY * dpr; + const modifiers = makeKeyboardModifiersBitfield(e); - editor.handle.onDoubleClick(e.clientX, e.clientY, buttons, modifiers); + editor.handle.onDoubleClick(scaledX, scaledY, buttons, modifiers); } function onMouseDown(e: MouseEvent) { @@ -268,8 +292,13 @@ export function createInputManager(editor: Editor, dialog: DialogState, portfoli if (isTargetingCanvas) { e.preventDefault(); + // Scale coordinates by device pixel ratio to fix offset on high-DPI devices like iPad + const dpr = getDevicePixelRatio(); + const scaledX = e.clientX * dpr; + const scaledY = e.clientY * dpr; + const modifiers = makeKeyboardModifiersBitfield(e); - editor.handle.onWheelScroll(e.clientX, e.clientY, e.buttons, e.deltaX, e.deltaY, e.deltaZ, modifiers); + editor.handle.onWheelScroll(scaledX, scaledY, e.buttons, e.deltaX, e.deltaY, e.deltaZ, modifiers); } } diff --git a/frontend/src/utility-functions/viewports.ts b/frontend/src/utility-functions/viewports.ts index 134ece0b31..9635ded227 100644 --- a/frontend/src/utility-functions/viewports.ts +++ b/frontend/src/utility-functions/viewports.ts @@ -2,9 +2,14 @@ import { type Editor } from "@graphite/editor"; export function updateBoundsOfViewports(editor: Editor) { const viewports = Array.from(window.document.querySelectorAll("[data-viewport-container]")); + + // Get device pixel ratio to scale bounds for high-DPI devices like iPad + const dpr = window.devicePixelRatio || 1; + const boundsOfViewports = viewports.map((canvas) => { const bounds = canvas.getBoundingClientRect(); - return [bounds.left, bounds.top, bounds.right, bounds.bottom]; + // Scale bounds by device pixel ratio to match scaled pointer coordinates + return [bounds.left * dpr, bounds.top * dpr, bounds.right * dpr, bounds.bottom * dpr]; }); const flattened = boundsOfViewports.flat(); From 705f2b3b460ede21a269019a8ac1c6d7b9bb638a Mon Sep 17 00:00:00 2001 From: sambhram1 Date: Sun, 26 Oct 2025 16:26:58 +0530 Subject: [PATCH 2/3] "ci/cd" --- .../src/components/widgets/inputs/NumberInput.svelte | 2 +- frontend/src/editor.ts | 3 ++- frontend/src/io-managers/input.ts | 12 ++++++------ frontend/src/messages.ts | 2 +- frontend/src/subscription-router.ts | 2 +- frontend/src/utility-functions/viewports.ts | 4 ++-- 6 files changed, 13 insertions(+), 12 deletions(-) diff --git a/frontend/src/components/widgets/inputs/NumberInput.svelte b/frontend/src/components/widgets/inputs/NumberInput.svelte index 6bdb0ce102..65a4cc4b25 100644 --- a/frontend/src/components/widgets/inputs/NumberInput.svelte +++ b/frontend/src/components/widgets/inputs/NumberInput.svelte @@ -1,9 +1,9 @@