Skip to content
MIZU.

SIG—10 Signature system

Annotator

Review pins on anything: drop numbered pins, discuss in threads, resolve and reopen, and find every conversation in the list beside the work.

View .md

Live — this one is real

Scenario

Illustrative review. Press C (or the Comment button), then click the draft to drop a pin; ⌘/Ctrl+Enter posts. Drag pins to move them, or use arrow keys on a focused pin.

Pricing page

3 open · 1 resolved

Plans for every team.

Start free, invite your team when the work needs it, and keep every draft.

Solo€0Up to 3 seats
Most chosenTeam€12Per seat, monthly
Enterprise—Volume and SSO

Press C for comment mode, then click the work or press Enter to place a pin. Arrow keys move a focused pin.

Usage

tsx
"use client";

import { useState } from "react";
import { Annotator, type Annotation } from "mizu-ui";

export function Example() {
  const field = (ground: string, mark: string) =>
    `data:image/svg+xml,${encodeURIComponent(`<svg xmlns="http://www.w3.org/2000/svg" width="720" height="360"><pattern id="d" width="36" height="36" patternUnits="userSpaceOnUse"><path d="M18 13l5 5-5 5-5-5z" fill="${mark}"/></pattern><rect width="720" height="360" fill="${ground}"/><rect width="720" height="360" fill="url(#d)"/></svg>`)}`;
  const [notes, setNotes] = useState<Annotation[]>([
    {
      id: "a",
      x: 0.3,
      y: 0.4,
      author: "Rin",
      body: "Can this headline be shorter?",
    },
  ]);
  return (
    <Annotator
      label="Homepage"
      author="You"
      annotations={notes}
      onAnnotationsChange={setNotes}
    >
      <img src={field("#141413", "#7e776b")} alt="Homepage draft" />
    </Annotator>
  );
}

It starts with "use client" because it keeps state or passes functions to components, so it pastes into a Next.js page as it is. Other React setups ignore the directive.

This code, running — no configuration beyond the data

Homepage

1 open

Homepage draft

Press C for comment mode, then click the work or press Enter to place a pin. Arrow keys move a focused pin.

Keyboard

C
Toggle comment mode
Enter
In comment mode: place a pin at the centre
Alt+←→↑↓
While writing: move the new pin (Shift: further)
⌘/Ctrl+Enter
Post the comment or reply
←→↑↓
On a pin: move it
Esc
Close the thread or discard the draft

Source & setup

Add this component to your project with the shadcn CLI. The command copies its source into your configured UI directory, with base.css, Mizu’s tokens, and the stylesheets that hold its rules. Each rule lives in one stylesheet, so components you add together never repeat CSS. In a project without a components.json, run npx shadcn@latest init 0xuser64bit/mizu/preset first: plain init installs shadcn’s theme into your global CSS. Then load the fonts.

sh
npx shadcn@latest add 0xuser64bit/mizu/annotator

Every component imports from its own path, its name in kebab case. To paste the example, replace its mizu-ui import with:

tsx
import { Annotator, type Annotation } from "@/components/ui/mizu/annotator";

For npm imports, import mizu-ui/styles.css once. Fonts are optional via mizu-ui/fonts.css. Override --mizu-* tokens or use className for local styling. Requires React and Motion. A Client Component: its source starts with “use client”.

Inspect signature/Annotator.tsx

Source is included in the npm package under src/signature/Annotator.tsx.

Open full source ↗

Props

PropTypeDefaultDescription
label / childrenstring / ReactNode—Region name and the work under review: an image, a page or a live composition.
annotations / defaultAnnotations / onAnnotationsChangeAnnotation[]—id, x and y (0–1 of the surface), author, body, time, resolved and replies.
author / nowstring—Name and time label for new comments and replies. Omit author for read-only review.
selected / defaultSelected / onSelectedChangestring | null—The open thread.
createId() => string—Id factory for new comments and replies.

Accessibility

Pins are buttons named with their number, author, state and text, in reading order; threads are labelled dialogs that return focus to their pin. C toggles comment mode, where Enter places a pin that arrow keys (or Alt+arrows while typing) move before posting. Every action is announced; the comment list offers the same threads without the surface.

Motion

Pins drop in on a spring and send out a single impact ring. Threads unfold from the side of their pin; a pin being placed breathes until it is posted. Resolving settles the pin into a quiet outline. Reduced motion places and opens everything directly.

Works alongside