ananyajoshi Claude Opus 5 (1M context) commited on
Commit
8508ded
·
1 Parent(s): 61929ab

Keep the ambient float; freeze it only while the pointer is inside

Browse files

Supersedes the previous attempt, which fixed the mis-click by refusing
the perpetual float to any surface holding a control. That worked, but
it took the motion off the main panels — the wrong trade.

The float now runs exactly as before and simply stops advancing while
the pointer is inside a surface the user can click into, resuming on
pointerleave. A click only fires when mousedown and mouseup land on the
same element, so the surface has to be still for the moment you are
actually aiming at it — and nowhere else.

Uses the existing holdFloat/resumeFloat pair, the same handoff tilt3d
already performs, so the float remains the sole author of the transform
and merely pauses. Pausing holds the current transform rather than
clearing it, so nothing snaps.

Measured on the running app:
pointer away -> 6.7px x / 2.5px y drift (motion alive)
pointer inside -> 0.0px / 0.0px (steady to click)
pointer leaves -> 9.1px / 4.3px (drift resumes)
Save Configuration and Run API Check both land on the first click; 3
surfaces still float, and the presentation-only one drifts even under
the cursor, as before.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

Files changed (1) hide show
  1. app/ui/motion_runtime.py +31 -0
app/ui/motion_runtime.py CHANGED
@@ -145,6 +145,9 @@ _DRIVER = r"""
145
  repeat: Infinity,
146
  ease: 'easeInOut'
147
  });
 
 
 
148
  }
149
 
150
  function holdFloat(el) {
@@ -155,6 +158,31 @@ _DRIVER = r"""
155
  return false;
156
  }
157
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
158
  // Pointer tilt. Hands over from the float and hands back on leave, because
159
  // two animations writing the same transform component fight each other.
160
  function tilt3d(el, max) {
@@ -349,6 +377,9 @@ _DRIVER = r"""
349
  z: wave(17, (i % 4) / 4, 17),
350
  rotateX: wave(2.4, (i % 4) / 4 + 0.25)
351
  }, { duration: 6.5, repeat: Infinity, ease: 'easeInOut' });
 
 
 
352
  });
353
 
354
  // The mark is a compass. Turning is the one thing it should do.
 
145
  repeat: Infinity,
146
  ease: 'easeInOut'
147
  });
148
+ // Keeps the drift, but holds it still while the pointer is inside a
149
+ // surface the user can click into. See steadyForPointer below.
150
+ steadyForPointer(el);
151
  }
152
 
153
  function holdFloat(el) {
 
158
  return false;
159
  }
160
 
161
+ // A surface that carries controls keeps its ambient float — it just holds
162
+ // still while you are aiming at something inside it.
163
+ //
164
+ // A `click` fires only when mousedown and mouseup land on the SAME element.
165
+ // A panel drifting a few pixels moves its buttons out from under the cursor
166
+ // between those two events, so clicks are silently swallowed and the button
167
+ // appears to need several stabs before one registers. Freezing on
168
+ // pointerenter makes the surface stationary for exactly as long as the
169
+ // pointer is inside it, and the drift resumes on the way out.
170
+ //
171
+ // This is the same handoff tilt3d performs, through the same pause/play
172
+ // pair, so nothing new ever owns the transform: the float stays its sole
173
+ // author and simply stops advancing. Pausing (rather than clearing) holds
174
+ // the current transform, so the surface never snaps.
175
+ var CONTROLS = 'button, input, select, textarea, a[href], [role="button"], ' +
176
+ '[role="tab"], [role="option"], [contenteditable="true"]';
177
+
178
+ function steadyForPointer(el) {
179
+ if (el.dataset.upsSteady) return;
180
+ if (!el.querySelector(CONTROLS)) return; // presentation surfaces drift freely
181
+ el.dataset.upsSteady = '1';
182
+ el.addEventListener('pointerenter', function () { holdFloat(el); });
183
+ el.addEventListener('pointerleave', function () { resumeFloat(el); });
184
+ }
185
+
186
  // Pointer tilt. Hands over from the float and hands back on leave, because
187
  // two animations writing the same transform component fight each other.
188
  function tilt3d(el, max) {
 
377
  z: wave(17, (i % 4) / 4, 17),
378
  rotateX: wave(2.4, (i % 4) / 4 + 0.25)
379
  }, { duration: 6.5, repeat: Infinity, ease: 'easeInOut' });
380
+ // Same rule as float3d: an entry that never settles holds still while
381
+ // the pointer is inside it, in case it ever carries a link or control.
382
+ steadyForPointer(el);
383
  });
384
 
385
  // The mark is a compass. Turning is the one thing it should do.