Skip to content

Pendulum Menu

Menu items that hang from a rail and swing on real pendulum physics, nudging their neighbours.

DOM + CSS0 deps1 file · 4 KB TSX

Proplayfuleditorial
Preview

Props

2600
1.1

The source is part of Pro

$27/month or $179 once. See Pro

No runtime dependencies
"use client";

import { useCallback, useRef } from "react";

type Item = { label: string; L: number; theta: number; omega: number };

export function PendulumMenu({
  labels = ["Overview", "Projects", "Archive", "Contact"],
  gravity = 2600,
  damping = 1.1,
  accent = "#d6ff00",
  onSelect,
}: {
  labels?: string[];
  gravity?: number;
  damping?: number;
  /** Colour of the current item's label. */
  accent?: string;

  // ---------------------------------------------------------------
  // Full source available with a viberdy Pro subscription.
  // https://viberdy.dev/pricing
  // ---------------------------------------------------------------
}
Details

About this animation

This is a menu built on the actual pendulum equation rather than on easing curves that resemble one. The decision that carries it is keeping the sine: nearly every implementation substitutes the small-angle approximation, because it reduces the system to a simple spring and is easier to reason about — but that substitution makes every item swing at an identical rate no matter how hard it was pushed, and the amplitude-dependent period is precisely what makes a pendulum read as a physical object. A wide swing has to take visibly longer than a narrow one. Two supporting details keep it stable and legible. The integrator runs at a fixed hundred-and-twentieth-of-a-second substep behind an accumulator, because feeding a variable frame delta into it makes the simulation explode the first time a frame drops, and the incoming delta is clamped so a backgrounded tab does not return and run hundreds of steps at once. And the transform origin sits above each item rather than inside it, which is the difference between swinging on an arc and spinning in place. The stagger is not authored at all: each item hangs from a slightly longer arm, so it has a longer natural period and the row fans apart on its own.

Curator’s note

The one line that matters is Math.sin(theta). Linearise it and you get four identical springs; keep it and you get a pendulum.

Pairs well with

Pro
Trending
Pro
Pro