newOS for Developers

Back to Overview

useFlyawayAnimation

hook47 lines

Provides a flyaway animation effect for votes/powerups, showing "+1 CWATT" floating upward with random angle on click.

Source Path
apps/web/hooks/useFlyawayAnimation.tsx
Package

@newos/web

Signature

useFlyawayAnimation(): {
  containerRef: React.RefObject<any>;      // Ref for positioning container
  animatedFlyAway: {                       // Current animation state
    id: number;
    value: string | number | ReactNode;
    x: number;
    y: number;
    angle: number;
  } | undefined;
  handleClick: (e: MouseEvent | TouchEvent) => void;  // Trigger animation
  setFlyAwayComponent: (component: ReactNode) => void; // Customize display
}

Animation State Properties

PropertyTypeDescription
idnumberUnique ID (Date.now()) for React key
valueReactNodeContent to display (default: +1CWATT)
xnumberX position relative to container
ynumberY position relative to container
anglenumberRandom rotation (-45° to +45°)

Key Features

Click Position Tracking

Animation starts at exact click/touch position within the container. Handles both touchend and click events.

Random Angle

Each animation gets a random angle between -45° and +45° for visual variety.

Auto-Cleanup

Animation state is automatically cleared via setTimeoutafter 2000ms.

Customizable Content

Use setFlyAwayComponent to change the displayed content. Default shows +1CWATT in #E3FF93 color.

Responsive Sizing

Default component uses fontSize: 24px on mobile,auto on wide screens.

Usage Example

import { useFlyawayAnimation } from "@/hooks/useFlyawayAnimation";

function VoteButton({ onVote }) {
  const { 
    containerRef, 
    animatedFlyAway, 
    handleClick,
    setFlyAwayComponent 
  } = useFlyawayAnimation();

  // Optional: customize display
  useEffect(() => {
    setFlyAwayComponent(
      <span style={{ color: "#E3FF93", fontSize: "48px" }}>+⚡</span>
    );
  }, []);

  const onClick = (e) => {
    handleClick(e);  // Trigger animation
    onVote();        // Perform vote action
  };

  return (
    <div ref={containerRef} style={{ position: "relative" }}>
      <button onClick={onClick}>Vote</button>
      
      {animatedFlyAway && (
        <div
          key={animatedFlyAway.id}
          className="flyaway-animation"
          style={{
            position: "absolute",
            left: animatedFlyAway.x,
            top: animatedFlyAway.y,
            transform: `rotate(${animatedFlyAway.angle}deg)`,
          }}
        >
          {animatedFlyAway.value}
        </div>
      )}
    </div>
  );
}

Edge Cases & Gotchas

containerRef Required — Must attach containerRef to a positioned parent element for correct positioning.
Left-Click Only — Mouse events only trigger on e.button === 0(left click). Right-clicks are ignored.
Touch Event Coordinates — For touch events, uses e.pageX/pageYinstead of e.clientX/clientY.
CSS Animation — You must provide CSS for the actual flyaway animation (e.g., translateY, opacity fade). This hook only provides positioning.