mirror of
https://github.com/openswarm-ai/openswarm.git
synced 2026-09-08 02:37:45 +02:00
[eric] windows: onboarding cursor eases via cursorStore-driven css transition (snaps while tracking, eases on moveTo) to match the mac spring
This commit is contained in:
@@ -67,10 +67,10 @@ const AgenticCursor = forwardRef<AgenticCursorHandle>((_props, ref) => {
|
||||
|
||||
const trackerRef = useRef<{ stop: () => void } | null>(null);
|
||||
|
||||
// Mirrored into cursorStore so popups follow without re-running through Framer's animation pipeline.
|
||||
const writePos = (x: number, y: number, vis = true) => {
|
||||
// Mirrored into cursorStore so popups follow without re-running through Framer's animation pipeline. `instant` controls the Windows CSS-transition fallback: true = snap (tracking), false = ease (moveTo/fadeOut). No-op on Mac.
|
||||
const writePos = (x: number, y: number, vis = true, instant = true) => {
|
||||
posRef.current = { x, y };
|
||||
cursorStore.set({ x, y, visible: vis });
|
||||
cursorStore.set({ x, y, visible: vis, instant });
|
||||
};
|
||||
|
||||
const stopTrackingInternal = () => {
|
||||
@@ -100,17 +100,18 @@ const AgenticCursor = forwardRef<AgenticCursorHandle>((_props, ref) => {
|
||||
async moveTo(x, y, transition) {
|
||||
// Stop prior tracker so it doesn't snap the cursor back to its old anchor mid-animation.
|
||||
stopTrackingInternal();
|
||||
// instant=false so the Windows CSS-transition eases here (mirrors Mac's spring controls.start).
|
||||
writePos(x, y, true, false);
|
||||
await controls.start({
|
||||
x,
|
||||
y,
|
||||
transition: transition ?? SPRING,
|
||||
});
|
||||
writePos(x, y, true);
|
||||
},
|
||||
async fadeOut(to) {
|
||||
stopTrackingInternal();
|
||||
writePos(to.x, to.y, true, false);
|
||||
await controls.start({ x: to.x, y: to.y, transition: SPRING });
|
||||
writePos(to.x, to.y, true);
|
||||
await controls.start({
|
||||
opacity: 0,
|
||||
scale: 0.5,
|
||||
@@ -262,8 +263,8 @@ const AgenticCursor = forwardRef<AgenticCursorHandle>((_props, ref) => {
|
||||
...(IS_WIN
|
||||
? {
|
||||
transform: `translate(${storePos.x}px, ${storePos.y}px)`,
|
||||
// Closest CSS approximation of the Mac spring (stiffness 260, damping 26): a softly easing ~420ms cubic-bezier. Without this the cursor teleports because the shim strips Framer's spring runtime.
|
||||
transition: 'transform 420ms cubic-bezier(0.22, 1, 0.36, 1)',
|
||||
// Closest CSS approximation of the Mac spring (stiffness 260, damping 26): a softly easing ~420ms cubic-bezier for moveTo/fadeOut. Tracking sets instant=true so the cursor snaps to its target each frame instead of perpetually lagging behind.
|
||||
transition: storePos.instant ? 'none' : 'transform 420ms cubic-bezier(0.22, 1, 0.36, 1)',
|
||||
willChange: 'transform',
|
||||
}
|
||||
: null),
|
||||
|
||||
@@ -6,9 +6,11 @@ interface CursorPos {
|
||||
x: number;
|
||||
y: number;
|
||||
visible: boolean;
|
||||
// Windows-only: the motionWin shim strips Framer's spring, so the cursor wrapper eases via CSS transition. `instant` tells it to disable the transition for this update — set true while tracking a (mostly stationary) element so the cursor snaps like Mac's controls.set, false for moveTo/fadeOut so it eases like controls.start. Ignored on Mac (Framer drives the motion).
|
||||
instant: boolean;
|
||||
}
|
||||
|
||||
let state: CursorPos = { x: 0, y: 0, visible: false };
|
||||
let state: CursorPos = { x: 0, y: 0, visible: false, instant: true };
|
||||
let pendingState: CursorPos | null = null;
|
||||
const listeners = new Set<() => void>();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user