Skip to content

fix(curves): make curve endpoints easy to grab and drag - #1853

Merged
CyberTimon merged 1 commit into
CyberTimon:mainfrom
Araoo:fix/curves-endpoint-dragging
Oct 6, 2026
Merged

CyberTimon merged 1 commit into
CyberTimon:mainfrom
Araoo:fix/curves-endpoint-dragging

Conversation

@Araoo

@Araoo Araoo commented Oct 6, 2026

Copy link
Copy Markdown
Contributor

Description

The curve endpoints (bottom-left and top-right) are hard to grab and drag in point curve mode: a click often creates a new point next to them, and once grabbed they tend to stay "stuck" on the edge.

There are two separate causes:

1. Points can't leave the left/right edge with slow mouse moves (regression from a683220).
Since the fine adjust mode, dragging is incremental: each move adds its delta to accumulatedPointRef. The edge snap (x < 5 → 0, x > 250 → 255) was then written back into that accumulator. Moving a point at x = 0 by 1–3 units per mousemove gets snapped back to 0 on every event, so it only leaves the edge if a single event moves it more than 5 units (i.e. a fast flick). Vertical movement isn't snapped, so the point slides up and down but feels glued horizontally.

The same commit also never initialized lastPointerRef / accumulatedSplitRef when starting to drag a parametric splitter, so the splitter could jump on the first move.

2. Narrow misses create a new point.
Point handles are r="6" circles in a 255-unit viewBox (~12 px wide on a typical panel), and at the corners part of the handle overflows the graph. A click that misses by a couple of pixels lands on the container and handleContainerStart inserts a new point right next to the endpoint. Clicks in the container padding are clamped to x = 0 / 255, which stacks a second point on the same x as the endpoint; that point is rendered on top and blocks the original one (prevX + 0.01 constraint), adding to the "stuck" feeling.

Type of Change

  • Bug fix
  • New feature
  • Breaking change
  • Performance improvement
  • Code refactoring
  • Documentation update
  • UI/UX improvement
  • Build/CI or Dependency update

Changes Made

  • handleMove: the accumulator keeps the unsnapped position (only clamped between neighbours); the edge snap is applied to the emitted value only. Snapping near the edges still works, but slow drags now accumulate and leave the edge normally.
  • Parametric splitter: onMouseDown / onTouchStart now initialize lastPointerRef and accumulatedSplitRef from the current pointer and split value.
  • handleContainerStart: before creating a point, look for the nearest existing point in screen pixels; if it is within 12 px (POINT_HIT_RADIUS_PX), grab it via handlePointStart instead. Using screen pixels keeps the tolerance constant whatever the panel width.
  • handleContainerStart: never create a point within 1 unit of an existing point's x (MIN_POINT_GAP_X), which prevents the duplicated endpoint from padding clicks.
  • onDragStateChange(true) is only called once a point is actually created or grabbed.

Screenshots/Videos

Testing

  • These changes were tested locally by a human and confirmed to work.
  • I haven't added any automated tests to the code because the codebase currently lacks a test suite.

Tested scenarios:

  1. Slowly dragging the bottom-left and top-right endpoints inwards: they leave the edge without needing a fast flick.
  2. Clicking 5–10 px away from an endpoint (including in the padding): the existing point is grabbed, no new point is created.
  3. Shift/Alt fine adjust drag still works as before.
  4. Parametric mode: dragging a splitter no longer jumps on the first move.
  5. Clicking elsewhere on the graph still adds a point.

Test Configuration:

  • OS: macOS 26.6.2
  • Hardware: Apple M4 Pro

Checklist

  • My code follows the project's code style
  • I haven't added unnecessary AI-generated code comments
  • My changes generate no new warnings or errors

Additional Notes

tsc passes and Prettier is clean. ESLint reports no new errors on Curves.tsx (the remaining ones are pre-existing no-explicit-any).

AI Disclaimer:

Please state the involvement of AI in this PR:

  • This PR is created by an AI agent
  • This PR is mostly AI-generated but edited/merged together by a human
  • This PR was handwritten with AI assistance (spell check, logic suggestions, error resolving)
  • This PR contains only blood, sweat, and coffee (AI-free)

- Keep the unsnapped position in the drag accumulator: writing the
  edge-snapped value back made points at x=0/255 unable to leave the edge
  with slow mouse moves (regression from the fine adjust mode).
- Initialize the pointer and accumulator when dragging a parametric
  splitter, so it no longer jumps on the first move.
- Clicking within 12px of an existing point grabs it instead of adding a
  new one, and no point is created on an x already used by another point.
@Araoo
Araoo requested a review from CyberTimon as a code owner October 6, 2026 11:30
@CyberTimon

Copy link
Copy Markdown
Owner

LGTM, thanks a lot for the fix!

@CyberTimon
CyberTimon merged commit 37a2fcd into CyberTimon:main Oct 6, 2026
CyberTimon added a commit that referenced this pull request Oct 6, 2026
@Araoo
Araoo deleted the fix/curves-endpoint-dragging branch October 6, 2026 12:16
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.

2 participants