# Pro installation and APIs

## Access

Core installs publicly from npm. Pro is a separate package delivered through Dots' authenticated registry, not npmjs. A $149 USD one-time purchase includes Pro and Studio. This skill is public; it is not a license or install credential.

Add to the project's `.npmrc` without replacing unrelated settings:

```ini
@dots-swarm:registry=https://dotsui.dev/api/registry/
//dotsui.dev/api/registry/:_authToken=${DOTS_TOKEN}
```

The owner creates an install token at https://dotsui.dev/account and sets `DOTS_TOKEN` privately in their shell or build environment. Do not embed a literal token in `.npmrc`, source, logs, copied prompts, client code, or a public environment variable. Do not request a secret in chat. If access is missing, complete independent work and explain the required setup.

```sh
npm install dots-swarm @dots-swarm/pro
```

Use matching compatible alpha versions. Keep the lockfile and placeholder `.npmrc`; set the CI secret before `npm ci`. The private registry protects installation; deployed client animations do not call it to check a license.

## Extra shapes

```tsx
"use client";
import { DotSwarm } from "dots-swarm";
import { getProShapePoints, getProShapeMotion } from "@dots-swarm/pro";

const points = getProShapePoints("torus", 1000);
const motion = getProShapeMotion("torus");

export function Torus() {
  return <DotSwarm points={points} motion={motion} count={1000}
    style={{ height: 340 }} label="Rotating torus" />;
}
```

Use `PRO_SHAPES` and `proShapeInfo` for exact IDs. A Pro ID does not belong in the core `DotSwarm.shape` prop. `proFormation(id)` returns its points and motion, plus metadata. For named Pro steps in `DotsSequencePlayer` or `DotsTimelinePlayer`, explicitly pass `shapes={proShapes}` from `@dots-swarm/pro`. Missing registration produces a missing-shape error.

## Coordinated timelines

`DotsTimeline` from `@dots-swarm/pro/timeline` accepts `{ version: 1, duration, loop, tracks, labels?, cues?, gates? }`. Each track has `id` and `clips`; each clip has `{ id, at, duration, value: { shape, color?, ... } }`. Times are seconds; clips must fit the timeline. Overlap clips for transitions.

```tsx
"use client";
import { useEffect, useMemo } from "react";
import { DotsTimeline } from "@dots-swarm/pro/timeline";
import { DotsTimelinePlayer } from "@dots-swarm/pro/react";

export function TwoStates() {
  const timeline = useMemo(() => new DotsTimeline({
    version: 1, duration: 10, loop: true,
    tracks: [{ id: "assistant", clips: [
      { id: "listen", at: 0, duration: 6, value: { shape: "cloud" } },
      { id: "done", at: 4, duration: 6, value: { shape: "check" } },
    ] }],
  }), []);
  useEffect(() => { timeline.play(); return () => { timeline.pause(); }; }, [timeline]);
  return <DotsTimelinePlayer timeline={timeline} style={{ height: 340 }} />;
}
```

The player or `useDotsTimeline` connects the clock. Use `play`, `pause`, `restart`, `seek(secondsOrLabel)`, and `emit(event,payload)`; gates resume only on their matching event. Core `DotsSequence` is sufficient for one simple ordered chain.

## Other entrypoints

| Import path | Exports and purpose |
| --- | --- |
| `@dots-swarm/pro/transitions` | `partitionPoints`, `transitionPoints`: split a fixed pool and interpolate along paths with wave/stagger |
| `@dots-swarm/pro/physics` | `ProSwarmPhysics`, `circleCollider`, `polygonCollider`: fields, constraints, and additional collisions |
| `@dots-swarm/pro/interactions` | `useSwarmGesture`: pointer/touch field for attraction or repulsion; `enabled` toggles capture and `touchAction: "pan-y"` preserves vertical scrolling in previews |
| `@dots-swarm/pro/events` | `DotsEventGraph`: named events, delayed commands, registered targets, cleanup |
| `@dots-swarm/pro/formations` | `createFormation`: parameterized living geometry; consult types for supported kinds |
| `@dots-swarm/pro/avatar` | `SwarmAvatar`, `createAvatarRenderer`: configurable solid characters |

For forces, memoize `createPhysics(points) => new ProSwarmPhysics(points, optionsOrGetter)` and pass it to `SwarmSurface`. A getter can read the current gesture field without resetting physics on every pointer move.

For externally animated points from `transitionPoints` or `createFormation`, drive progress/time with a cleaned-up clock and set `DotSwarm transitionDuration={0}`. Otherwise each frame restarts a morph. Keep count stable. Do not turn a single sampled frame into a permanently frozen formation.

`DotsEventGraph` accepts `{version:1,nodes}`; a node includes `id`, `event`, optional `delay`, `commands: [{target,method,value?}]`, optional `emit`. Register target handlers in an effect, unsubscribe and `dispose()` on cleanup. Emit real business completion events from real results rather than using a demo delay as a network-success signal.

## Avatars

```tsx
"use client";
import { useRef, useState } from "react";
import { swarmActions, type AvatarExpression, type SwarmSurfaceHandle } from "dots-swarm";
import { SwarmAvatar } from "@dots-swarm/pro/avatar";

export function LittleFriend() {
  const avatar = useRef<SwarmSurfaceHandle>(null);
  const [expression, setExpression] = useState<AvatarExpression>("curious");
  return <>
    <SwarmAvatar ref={avatar} expression={expression} silhouette="pebble"
      color="#82b5fa" eyeScale={1.45} speech={0} style={{ height: 360 }}
      onActionComplete={action => {
        if (action.type === "explode") {
          setExpression("dizzy");
          avatar.current?.act(swarmActions.reform({ duration: 2 }));
        }
      }} />
    <button onClick={() => {
      setExpression("excited");
      avatar.current?.act(swarmActions.explode({ anticipation: 1.4, strength: 1250, duration: 2 }));
    }}>Blow this little guy up</button>
  </>;
}
```

Silhouettes: `orb`, `pebble`, `squircle`. Expressions: `neutral`, `happy`, `curious`, `surprised`, `excited`, `dizzy`. `speech` is an existing normalized 0–1 audio level; use 0 for a silent avatar. Do not add microphone permissions or audio streaming unless requested. Use the surface's colliders/viewport options if the user wants dots to scatter against surrounding UI.
