← Back to Skills Marketplace
frank17008

image-annotation-usage

by Frank · GitHub ↗ · v1.0.0 · MIT-0
cross-platform ✓ Security Clean
2
Downloads
0
Stars
0
Active Installs
1
Versions
Install in OpenClaw
/install image-annotation-usage
Description
Use when integrating @frank17008/image-annotation React component into web applications, including basic setup, controlled/uncontrolled mode, custom image up...
README (SKILL.md)

Image Annotation Component Usage

Overview

@frank17008/image-annotation is a React + TypeScript image annotation component with Canvas 2D. Supports rectangle, circle, arrow, text, and freehand tools with undo/redo, drag, export, keyboard shortcuts, zoom/pan, and DPR-aware rendering.

Package location: packages/image-annotation/src/ Published path: @frank17008/image-annotation

When to Use

Trigger phrases:

  • "How to integrate image annotation component"
  • "Add annotation to my React app"
  • "Canvas blank even though image loads"
  • "Annotations not saving"
  • "Custom image upload with annotation"
  • "Controlled mode not working"
  • "HiDPI/Retina display blurry"

Installation

pnpm add @frank17008/image-annotation
# or
npm install @frank17008/image-annotation

Basic Integration

Minimal Setup

import { useState } from 'react';
import { ImageAnnotation, type Annotation } from '@frank17008/image-annotation';
import '@frank17008/image-annotation/dist/index.css';

export default function App() {
  const [annotations, setAnnotations] = useState\x3CAnnotation[]>([]);

  return (
    \x3Cdiv style={{ height: 600 }}>
      \x3CImageAnnotation
        src="https://example.com/image.jpg"
        onChange={setAnnotations}
      />
    \x3C/div>
  );
}

Critical: Parent container MUST have explicit height. Without it, canvas has 0×0 dimensions → blank canvas.

Type Import

Always use explicit type import for TypeScript:

import type { Annotation, ToolType } from '@frank17008/image-annotation';
// or
import { type Annotation, type ToolType } from '@frank17008/image-annotation';

Controlled vs Uncontrolled Mode

Uncontrolled (Default)

\x3CImageAnnotation
  src="image.jpg"
  onChange={(annotations) => console.log(annotations)}
/>

The component manages its own state internally.

Controlled (External State)

const [myAnnotations, setMyAnnotations] = useState\x3CAnnotation[]>([]);

\x3CImageAnnotation
  src="image.jpg"
  value={myAnnotations}
  onChange={setMyAnnotations}
/>

Rules:

  1. value → external annotations (read-only for component)
  2. onChange → called when annotations change
  3. If both value and onChange provided → controlled mode
  4. If neither → uncontrolled mode
  5. If only value without onChange → React warning

Sync Controlled to Uncontrolled

\x3CImageAnnotation
  src={src}
  value={annotations}
  onChange={(newAnnotations) => {
    setAnnotations(newAnnotations);
    // Save to backend, localStorage, etc.
    saveToBackend(newAnnotations);
  }}
/>

Custom Image Upload

Pattern 1: External Button

import { useState, useRef } from 'react';
import { ImageAnnotation } from '@frank17008/image-annotation';

export function ImageUploader() {
  const [imageSrc, setImageSrc] = useState\x3Cstring | null>(null);
  const fileInputRef = useRef\x3CHTMLInputElement>(null);

  const handleFileChange = (e: React.ChangeEvent\x3CHTMLInputElement>) => {
    const file = e.target.files?.[0];
    if (!file) return;

    const reader = new FileReader();
    reader.onload = (event) => {
      const result = event.target?.result;
      if (typeof result === 'string') {
        setImageSrc(result); // base64 string
      }
    };
    reader.readAsDataURL(file);
    e.target.value = ''; // reset for same file re-select
  };

  return (
    \x3Cdiv style={{ height: 600 }}>
      \x3Cinput
        ref={fileInputRef}
        type="file"
        accept="image/*"
        onChange={handleFileChange}
        style={{ display: 'none' }}
      />
      \x3Cbutton onClick={() => fileInputRef.current?.click()}>
        Upload Image
      \x3C/button>
      {imageSrc && (
        \x3CImageAnnotation
          src={imageSrc}
          onChange={() => {}}
        />
      )}
    \x3C/div>
  );
}

Pattern 2: Component's Upload Button

const handleUpload = () => fileInputRef.current?.click();

\x3CImageAnnotation
  src={imageSrc}
  onChange={setAnnotations}
  onUpload={handleUpload}
/>

The component displays an upload button in toolbar when onUpload is provided.

Annotation Types Reference

// Rectangle annotation
{ type: 'rectangle', x: number, y: number, width: number, height: number, color: string, lineWidth?: number }

// Circle annotation
{ type: 'circle', x: number, y: number, radius: number, color: string, lineWidth?: number }

// Arrow annotation
{ type: 'arrow', x: number, y: number, toX: number, toY: number, color: string, lineWidth?: number }

// Text annotation
{ type: 'text', x: number, y: number, text: string, color: string, lineWidth?: number }

// Freehand annotation
{ type: 'freehand', points: Array\x3C{ x: number, y: number }>, color: string, lineWidth?: number }

Type Export

import type {
  Annotation,
  RectangleAnnotation,
  CircleAnnotation,
  ArrowAnnotation,
  TextAnnotation,
  FreehandAnnotation,
  ToolType,
  Point,
} from '@frank17008/image-annotation';

Props API

Prop Type Required Description
src string Image URL or base64
value Annotation[] Controlled annotations
onChange (annotations: Annotation[]) => void Annotation change callback
className string Container className
onUpload () => void Upload button callback

Zoom and Pan

Programmatic Zoom

const handleZoomIn = () => {
  // Component doesn't expose zoom API directly
  // Use keyboard shortcuts: Ctrl++
};

// Or via keyboard shortcuts (user must press):
// - Ctrl++ : Zoom in
// - Ctrl+- : Zoom out
// - Ctrl+0 : Reset zoom

Space + Drag Pan

Hold Space + drag to pan the canvas.

Zoom Ratio Display

The toolbar shows current zoom percentage (e.g., "100%", "150%").

Exporting Annotations

On Change Callback

\x3CImageAnnotation
  src={src}
  onChange={(annotations) => {
    // Save to database
    await saveAnnotations(imageId, annotations);

    // Or export as JSON
    const json = JSON.stringify(annotations, null, 2);
    download(json, 'annotations.json', 'application/json');
  }}
/>

Export Image with Annotations

Use the toolbar's export button, or programmatically:

import { download } from '@frank17008/image-annotation';
// Not currently exported - use toolbar button

Keyboard Shortcuts

Shortcut Action
Delete Delete selected annotation
Escape Cancel text input
Ctrl+Z Undo
Ctrl+Y / Ctrl+Shift+Z Redo
Ctrl++ / Ctrl+= Zoom in
Ctrl+- Zoom out
Ctrl+0 Reset zoom
Space + Drag Pan canvas

Styling Customization

CSS Variables

:root {
  --annotation-primary: #FF0000;
  --annotation-toolbar-bg: #FFFFFF;
}

Container Styling

\x3CImageAnnotation
  src={src}
  className="my-annotation-container"
/>
.my-annotation-container {
  border: 1px solid #ddd;
  border-radius: 8px;
}

Debugging Common Issues

Issue 1: Canvas Completely Blank

Symptoms:

  • Image loads successfully (network request completes)
  • Canvas area is empty/white

Root Causes and Solutions:

Cause Diagnosis Fix
Parent has no height Container has height: auto or no height set Set explicit height: style={{ height: 600 }}
DPR mismatch Retina/HiDPI display, canvas looks tiny Component handles DPR automatically
Image load error Check browser console for CORS errors Add crossOrigin="anonymous" to server
Zero canvas size Check canvas element dimensions Ensure parent has explicit dimensions

Issue 2: Annotations Not Saving

Symptoms:

  • Draw annotations but array remains empty
  • onChange callback never fires

Root Causes and Solutions:

Cause Diagnosis Fix
Stale state Using prev => prev incorrectly Pass new array directly: setAnnotations(newValue)
Missing onChange No callback provided Add onChange={setAnnotations}
Controlled conflict Both value and internal state Provide onChange with value

Correct pattern:

// WRONG - stale closure
onChange={(annotations) => {
  setAnnotations((prev) => [...prev, ...annotations]);
}}

// CORRECT - direct assignment
onChange={setAnnotations}

Issue 3: Blurry on HiDPI/Retina Displays

Diagnosis:

  • Canvas appears blurry or pixelated
  • Only happens on Retina displays

Root Cause: Missing devicePixelRatio scaling

Fix: The component handles DPR automatically since v1.x. Ensure:

  1. CSS import is included
  2. Parent container has proper dimensions

Issue 4: High-DPI Canvas Blank

Symptoms:

  • Works on standard displays
  • Blank on Retina/HiDPI

Root Cause: Canvas dimensions not scaled by devicePixelRatio

Diagnosis:

// In browser console
const canvas = document.querySelector('canvas');
console.log('Canvas size:', canvas.width, canvas.height);
console.log('Display size:', canvas.style.width, canvas.style.height);
console.log('DPR:', window.devicePixelRatio);

If canvas.width === canvas.style.width (not multiplied by DPR), this is the bug.

Issue 5: Text Annotation Not Updating

Symptoms:

  • Text tool selected
  • Click to add text
  • Text doesn't appear or doesn't save

Solution: Press Enter or click outside to commit text input.

Issue 6: Undo/Redo Not Working

Symptoms:

  • Press Ctrl+Z but nothing happens

Root Cause: No history to undo (first annotation can't be undone)

Issue 7: SSR/Next.js Issues

Symptoms:

  • "window is not defined"
  • Canvas only renders client-side

Solution:

'use client';
import dynamic from 'next/dynamic';

const ImageAnnotation = dynamic(
  () => import('@frank17008/image-annotation').then((mod) => mod.default),
  { ssr: false }
);

Build Commands

pnpm build:lib      # Build package to dist/
pnpm dev:lib       # Watch mode for library
pnpm start         # Run demo app
pnpm build:all    # Build everything

Dependencies

  • React 18+
  • TypeScript 4.5+
  • Canvas 2D API

Common Mistakes

❌ Forgetting CSS Import

// MISSING - component won't render correctly
import { ImageAnnotation } from '@frank17008/image-annotation';

// REQUIRED
import '@frank17008/image-annotation/dist/index.css';

❌ Parent Without Height

// WRONG - canvas has 0x0
\x3Cdiv>\x3CImageAnnotation src="..." />\x3C/div>

// CORRECT - explicit height
\x3Cdiv style={{ height: 600 }}>\x3CImageAnnotation src="..." />\x3C/div>

❌ Wrong Type Import

// WRONG
import { Annotation } from '@frank17008/image-annotation';

// CORRECT
import type { Annotation } from '@frank17008/image-annotation';

❌ Not Linking onChange with value

// WRONG - controlled without onChange (React warning)
\x3CImageAnnotation src="..." value={annotations} />

// CORRECT - controlled mode
\x3CImageAnnotation
  src="..."
  value={annotations}
  onChange={setAnnotations}
/>

Performance Tips

Large Images

For images > 5MB:

  1. Resize before passing to component
  2. Use appropriate container dimensions
  3. Consider lazy loading

Many Annotations (>100)

The component redraws on each change. For performance:

  1. Reduce lineWidth
  2. Simplify freehand paths (reduce point count)
Usage Guidance
This skill appears safe and purpose-aligned as a documentation-only guide. Treat the npm package installation like any third-party dependency: verify that the package is the one you intend to use before adding it to your project.
Capability Analysis
Type: OpenClaw Skill Name: image-annotation-usage Version: 1.0.0 The skill bundle provides comprehensive documentation and integration examples for a React-based image annotation component (@frank17008/image-annotation). The content in SKILL.md consists of standard React/TypeScript code snippets, API references, and troubleshooting guides for common UI issues like canvas rendering and state management. No evidence of data exfiltration, malicious execution, or prompt injection was found.
Capability Assessment
Purpose & Capability
The skill’s stated purpose is to help integrate a React image annotation component, and the provided content is consistent with setup, props, examples, and troubleshooting guidance.
Instruction Scope
The instructions are documentation-style examples and do not direct the agent to override user intent, run hidden actions, or perform autonomous changes.
Install Mechanism
The skill includes user-directed npm/pnpm installation commands for the React package. This is expected for the stated purpose, but users should still trust the package before adding it to a project.
Credentials
The examples are scoped to a React web app and browser-based image upload/annotation behavior. No credentials, system access, or unrelated data access are requested.
Persistence & Privilege
No persistent background process, elevated privilege, credential use, or autonomous execution mechanism is shown in the provided artifacts.
How to Use
  1. Make sure OpenClaw is installed (local or Docker)
  2. Run the install command in chat: /install image-annotation-usage
  3. After installation, invoke the skill by name or use /image-annotation-usage
  4. Provide required inputs per the skill's parameter spec and get structured output
Version History
v1.0.0
Initial release — concise integration and troubleshooting guide for the image annotation component. - Covers integrating @frank17008/image-annotation into React apps, including controlled/uncontrolled usage and custom image upload. - Details required parent container styling, common pitfalls (like blank canvas), and debugging tips. - Documents props, annotation types, keyboard shortcuts, and basic styling customization. - Provides usage patterns for exporting annotations and leveraging toolbar features. - Includes clear TypeScript usage guidance and typical integration code samples.
Metadata
Slug image-annotation-usage
Version 1.0.0
License MIT-0
All-time Installs 0
Active Installs 0
Total Versions 1
Frequently Asked Questions

What is image-annotation-usage?

Use when integrating @frank17008/image-annotation React component into web applications, including basic setup, controlled/uncontrolled mode, custom image up... It is an AI Agent Skill for Claude Code / OpenClaw, with 2 downloads so far.

How do I install image-annotation-usage?

Run "/install image-annotation-usage" in the OpenClaw or Claude Code chat to install it in one step — no extra setup required.

Is image-annotation-usage free?

Yes, image-annotation-usage is completely free, licensed under MIT-0. You can download, install and use it at no cost.

Which platforms does image-annotation-usage support?

image-annotation-usage is cross-platform and runs anywhere OpenClaw / Claude Code is available (cross-platform).

Who created image-annotation-usage?

It is built and maintained by Frank (@frank17008); the current version is v1.0.0.

💬 Comments