nikolas-sapa

Pole Shy

Component 3

About

A live cursor/collaboration name-label that pushes overlapping labels apart with a magnet-like physics simulation so the currently typing collaborator's label stays readable while others yield.

Built with React and Tailwind. Copy the prompt and paste it into Claude Code, Cursor or Lovable: your agent adds Pole Shy to your project and fits it to your theme.

Code

How Pole Shy is used: the demo's code. The component's own source comes with a free account.

Usage.tsx

"use client";

import PoleShy, { type PoleShyUser } from "@/components/ui/pole-shy";
import * as React from "react";

const baseUsers: PoleShyUser[] = [
  { id: "you", name: "You", x: 0.14, row: 0, typing: false },
  { id: "priya", name: "Priya Nair", x: 0.3, row: 0, typing: false },
  { id: "theo", name: "Theo Voss", x: 0.46, row: 0, typing: false },
  { id: "sam", name: "Sam Ochieng", x: 0.62, row: 0, typing: false },
  { id: "wren", name: "Wren Delacroix", x: 0.22, row: 1, typing: false },
  { id: "kai", name: "Kai Fujimori", x: 0.68, row: 1, typing: false },
];

export default function PoleShyDemo() {
  const [users, setUsers] = React.useState<PoleShyUser[]>(baseUsers);

  React.useEffect(() => {
    let i = 0;
    const interval = setInterval(() => {
      setUsers((prev) =>
        prev.map((u, idx) => ({ ...u, typing: idx === i % prev.length })),
      );
      i++;
    }, 1800);
    return () => clearInterval(interval);
  }, []);

  return (
    <div className="w-full max-w-2xl space-y-6 rounded-lg border border-border bg-card p-6">
      <div className="space-y-1">
        <h3 className="text-sm font-medium text-foreground">
          Section 2 — release notes
        </h3>
        <p className="text-xs text-muted-foreground">
          Several cursors crowd one line below. Type in the box — your label
          carries a stronger field while you&apos;re actively typing, and the
          others yield to make room.
        </p>
      </div>
      <PoleShy users={users} />
      <textarea
        placeholder="Type here — your caret label pushes the others aside"
        className="w-full resize-none rounded-md border border-border bg-background px-3 py-2 text-sm text-foreground placeholder:text-muted-foreground outline-none"
        rows={2}
        onChange={() =>
          setUsers((prev) =>
            prev.map((u) => (u.id === "you" ? { ...u, typing: true } : u)),
          )
        }
        onBlur={() =>
          setUsers((prev) =>
            prev.map((u) => (u.id === "you" ? { ...u, typing: false } : u)),
          )
        }
      />
    </div>
  );
}

More by nikolas-sapa

View all
  • Dye Whorl

    Dye Whorl

    138
  • Countdown Vapor Digits

    Countdown Vapor Digits

    122
  • Hero Burin Hatch

    Hero Burin Hatch

    62
  • Background ASCII Wake

    Background ASCII Wake

    54
  • Hero Text Ring Funnel

    Hero Text Ring Funnel

    48
  • Toast Gravity Stack

    Toast Gravity Stack

    46
  • Hero ASCII Schlieren

    Hero ASCII Schlieren

    45
  • Hero ASCII Reaction Front

    Hero ASCII Reaction Front

    41