Spaces:
Sleeping
Keep the ambient float; freeze it only while the pointer is inside
Browse filesSupersedes 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>
- app/ui/motion_runtime.py +31 -0
|
@@ -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.
|