ui-sniper
v3.2.5
Published
Visual feedback for AI coding agents
Readme
UI Sniper is an agent-agnostic visual feedback tool. Click elements on your page, add notes, and copy structured output that helps AI coding agents find the exact code you're referring to.
Install
npm install ui-sniper -DUsage
import { UI Sniper } from 'ui-sniper';
function App() {
return (
<>
<YourApp />
<UI Sniper />
</>
);
}The toolbar appears in the bottom-right corner. Click to activate, then click any element to annotate it.
Features
- Click to annotate – Click any element with automatic selector identification
- Text selection – Select text to annotate specific content
- Multi-select – Drag to select multiple elements at once
- Area selection – Drag to annotate any region, even empty space
- Animation pause (P) – Freeze all animations (CSS, JS, videos) to capture specific states
- X-Ray mode (X) – Reveal invisible structure, bounding boxes, and alignments
- Layout mode (L) – Drag, drop, edit text, or draw directly on the screen
- Detailed Help Panel – In-app guide detailing how, why, and the value of each mode
- Structured output – Copy markdown with selectors, positions, and context
- Programmatic access – Callback prop for direct integration with tools
- Dark/light mode – Toggle in settings, persists to localStorage
- Zero dependencies – Pure CSS animations, no runtime libraries
What's New in v3.2
- Rich Help Panel: A new built-in help panel explaining feature usage and value propositions.
- Improved Review Panel: Hover states, distinct color actions (Delete, Copy, Mark Done), and layout fixes preventing overlap.
- Enhanced Visual Feedback: The toolbar now has a distinct active border, and capturing screenshots accurately respects visibility states.
- Advanced X-Ray & Layout Tools: Reposition elements on the fly or inspect padding/margins before writing feedback.
- 100% Accurate Screenshots: Screenshots now capture the full
document.bodyand traverse parent elements for perfect semantic context, including all X-Ray wireframes and floating overlays.
Props
| Prop | Type | Default | Description |
|------|------|---------|-------------|
| onAnnotationAdd | (annotation: Annotation) => void | - | Called when an annotation is created |
| onAnnotationDelete | (annotation: Annotation) => void | - | Called when an annotation is deleted |
| onAnnotationUpdate | (annotation: Annotation) => void | - | Called when an annotation is edited |
| onAnnotationsClear | (annotations: Annotation[]) => void | - | Called when all annotations are cleared |
| onCopy | (markdown: string) => void | - | Callback with markdown output when copy is clicked |
| onSubmit | (output: string, annotations: Annotation[]) => void | - | Called when "Send Annotations" is clicked |
| copyToClipboard | boolean | true | Set to false to prevent writing to clipboard |
| endpoint | string | - | Server URL for Agent Sync (e.g., "http://localhost:4747") |
| sessionId | string | - | Pre-existing session ID to join |
| onSessionCreated | (sessionId: string) => void | - | Called when a new session is created |
| webhookUrl | string | - | Webhook URL to receive annotation events |
Programmatic Integration
Use callbacks to receive annotation data directly:
import { UI Sniper, type Annotation } from 'ui-sniper';
function App() {
const handleAnnotation = (annotation: Annotation) => {
// Structured data - no parsing needed
console.log(annotation.element); // "Button"
console.log(annotation.elementPath); // "body > div > button"
console.log(annotation.boundingBox); // { x, y, width, height }
console.log(annotation.cssClasses); // "btn btn-primary"
// Send to your agent, API, etc.
sendToAgent(annotation);
};
return (
<>
<YourApp />
<UI Sniper
onAnnotationAdd={handleAnnotation}
copyToClipboard={false} // Don't write to clipboard
/>
</>
);
}Annotation Type
type Annotation = {
id: string;
x: number; // % of viewport width
y: number; // px from top of document (absolute) OR viewport (if isFixed)
comment: string; // User's note
element: string; // e.g., "Button"
elementPath: string; // e.g., "body > div > button"
timestamp: number;
// Optional metadata (when available)
selectedText?: string;
boundingBox?: { x: number; y: number; width: number; height: number };
nearbyText?: string;
cssClasses?: string;
nearbyElements?: string;
computedStyles?: string;
fullPath?: string;
accessibility?: string;
isMultiSelect?: boolean;
isFixed?: boolean;
};Note: This is a simplified type. The full type includes additional fields for Agent Sync (
url,status,thread,reactComponents, etc.). See hara-xy.com/schema for the complete schema.
How it works
UI Sniper captures class names, selectors, and element positions so AI agents can grep for the exact code you're referring to. Instead of describing "the blue button in the sidebar," you give the agent .sidebar > button.primary and your feedback.
Requirements
- React 18+
- Desktop browser (mobile not supported)
Docs
Full documentation at hara-xy.com
License
© 2026 Shiva Patil
Licensed under PolyForm Shield 1.0.0
