npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@sargis-artashyan/react-smart-crop

v1.0.7

Published

Smart responsive image cropping using WebAssembly and computer vision. Faster than JS, privacy-focused, and client-side.

Downloads

1,013

Readme

react-smart-crop

Smart responsive image cropping for React powered by WebAssembly — 20-30x faster than JavaScript, privacy-focused, zero server latency

npm version npm downloads bundle size License: MIT React GitHub


🎯 Live Demo & Preview

Experience the smart crop algorithm in action:

🔗 Live Demo ← Click to see it in action


✨ Why WebAssembly?

Traditional JavaScript image analysis is computationally expensive and slow. react-smart-crop uses C++ compiled to WebAssembly for:

Performance Advantages

  • ⚡ 20-30x Faster — Near-native execution speed vs JavaScript
  • 🔒 100% Client-Side — No server uploads, no privacy concerns
  • 📉 Minimal Bandwidth — Only focal coordinates (2 integers), not pixel data
  • 🚀 Zero Server Latency — Instant results in browser
  • 📱 Mobile Optimized — Efficient resource usage on low-end devices

Smart Algorithm Features

  • Edge Detection — Finds important contours and transitions
  • Saliency Analysis — Scores regions by visual importance
  • Color Distribution — Analyzes background and foreground
  • Center-Bias Weighting — Biases toward natural composition
  • Skin Tone Prioritized — Ideal for portrait photos and face-centric images
  • Responsive Regions — 20×20 grid analysis for precision

📦 Installation

Requirements

  • React 18.0.0 or higher (including React 19.x)
  • Browser support: WebAssembly enabled

npm

npm install @sargis-artashyan/react-smart-crop

yarn

yarn add @sargis-artashyan/react-smart-crop

pnpm

pnpm add @sargis-artashyan/react-smart-crop

⚙️ Build Tool Configuration

Vite ✅ — Works out of the box! WASM is automatically handled.

Webpack 4/5 — Enable async WebAssembly support in webpack.config.js:

module.exports = {
  experiments: {
    asyncWebAssembly: true,
    layers: true
  }
};

🚀 Quick Start

Basic Usage

import React from 'react';
import { SmartCropImage } from '@sargis-artashyan/react-smart-crop';

export function MyGallery() {
  return (
    <div style={{ width: '100%', height: '400px' }}>
      <SmartCropImage 
        src="https://example.com/portrait.jpg"
        // Width and height accept: '100%', '100px', '50vw', '100rem', or numbers (treated as px)
        alt="Profile picture"
      />
    </div>
  );
}

With Debug Mode

Enable debug mode to visualize the detected focal point:

<SmartCropImage
  src="/images/photo.jpg"
  width={300}
  height={300}
  debug={true}  // Shows focal point indicator
  alt="Product image"
/>

Responsive Container

<div style={{
  width: '100%',
  maxWidth: '600px',
  aspectRatio: '16 / 9',
  margin: '0 auto'
}}>
  <SmartCropImage
    src="/images/banner.jpg"
    width="100%"
    height="100%"
    alt="Banner"
  />
</div>

Custom Styling with CSS

// Rounded avatar with shadow
<div style={{
  width: '120px',
  height: '120px',
  borderRadius: '50%',
  overflow: 'hidden',
  boxShadow: '0 4px 12px rgba(0,0,0,0.15)'
}}>
  <SmartCropImage
    src="user-profile.jpg"
    width="100%"
    height="100%"
    className="avatar-image"
    alt="User avatar"
  />
</div>

� Advanced Usage

Multi-Point Focal Detection

Detect multiple focal points in a single image using Non-Maximum Suppression algorithm:

import { useSmartCrop, type FocalPoint } from '@sargis-artashyan/react-smart-crop';

export function MultiPointAnalysis() {
  const { analyzeImage } = useSmartCrop();
  const [points, setPoints] = useState<FocalPoint[]>([]);

  const handleAnalyze = async (imageElement: HTMLImageElement) => {
    // Request 5 focal points instead of default 1
    const result = await analyzeImage(imageElement, 0, 5);
    
    if (Array.isArray(result)) {
      setPoints(result);
      result.forEach((point, idx) => {
        console.log(`Point ${idx + 1}: (${point.x.toFixed(1)}%, ${point.y.toFixed(1)}%) - Score: ${(point.score * 100).toFixed(0)}%`);
      });
    }
  };

  return (
    <div>
      <img id="img" src="complex-scene.jpg" alt="Scene with multiple subjects" />
      <button onClick={() => handleAnalyze(document.getElementById('img'))}>
        Find focal points
      </button>
    </div>
  );
}

How it works:

  1. Non-Maximum Suppression: After finding each focal point, the algorithm suppresses a region around it
  2. Score-Based Ranking: Each point receives a confidence score (0-1) based on saliency
  3. Adaptive Detection: Returns fewer points if image has less visual complexity
  4. Memory Safe: Automatically frees WASM heap memory

Use Cases:

  • 📸 Multi-Subject Photos: Portrait groups, crowd scenes
  • 🎬 Composition Analysis: Find all important regions for layout
  • 🤖 AI Training Data: Generate focal point labels for ML models
  • 🎨 Design Tools: Smart guides for optimal crop regions

Custom Hook Implementation

import { useSmartCrop } from '@sargis-artashyan/react-smart-crop';
import { useRef, useState } from 'react';

export function CustomCropAnalyzer() {
  const imgRef = useRef<HTMLImageElement>(null);
  const { analyzeImage, cancelAnalysis, updatePriority } = useSmartCrop();
  const [result, setResult] = useState(null);

  // Single focal point (default)
  const analyzeSingle = async () => {
    const result = await analyzeImage(imgRef.current, 0); // priority 0 = visible
    setResult(result);
  };

  // Multiple focal points
  const analyzeMulti = async (count: number) => {
    const result = await analyzeImage(imgRef.current, 1, count); // priority 1 = preload
    setResult(result);
  };

  // Change priority of queued task
  const prioritizeCurrentTask = () => {
    updatePriority(0); // Move to high priority queue
  };

  // Cancel ongoing analysis
  const stopAnalysis = () => {
    cancelAnalysis();
    setResult(null);
  };

  return (
    <>
      <img ref={imgRef} src="photo.jpg" alt="Analysis target" />
      <button onClick={analyzeSingle}>Analyze Single Point</button>
      <button onClick={() => analyzeMulti(5)}>Analyze 5 Points</button>
      <button onClick={prioritizeCurrentTask}>Prioritize</button>
      <button onClick={stopAnalysis}>Cancel</button>
      {result && (
        <div>
          {Array.isArray(result) ? (
            <p>Found {result.length} focal points</p>
          ) : (
            <p>Focal point: ({result.x}%, {result.y}%)</p>
          )}
        </div>
      )}
    </>
  );
}

TypeScript Types

// Single focal point (backward compatible)
interface SmartPoint {
  x: number;  // Percentage 0-100
  y: number;  // Percentage 0-100
}

// Multiple focal points (with confidence scores)
interface FocalPoint {
  x: number;      // Percentage 0-100
  y: number;      // Percentage 0-100
  score: number;  // Confidence 0-1 (higher = more important)
}

// Hook return type
type AnalysisResult = SmartPoint | FocalPoint[] | null;

📚 API Reference

SmartCropImage Component Props

| Prop | Type | Default | Description | |------|------|---------|-------------| | src | string | required | URL or path to the image to process. Must support CORS if cross-origin. | | width | number \| string | '100%' | Width of the container: '100%', '50px', '50vw', '10rem', or 300 (treated as px) | | height | number \| string | '100%' | Height of the container: '100px', '50vh', '10rem', or 300 (treated as px) | | alt | string | '' | Alternative text for accessibility. Recommended. | | debug | boolean | false | Show focal point visualization with pulsing indicator. Useful for testing. | | className | string | '' | Custom CSS class applied to the container. For styling/theming. | | enableBlurUp | boolean | true | Show blur-up placeholder during analysis (improves perceived performance). | | placeholderColor | string | '#e2e8f0' | Background color of blur-up placeholder SVG. Any valid CSS color. |

Hook: useSmartCrop()

const { analyzeImage, cancelAnalysis, updatePriority, isReady } = useSmartCrop();

// Analyze single point (backward compatible)
const result: SmartPoint | null = await analyzeImage(source, priority);

// Analyze multiple points (new feature)
const results: FocalPoint[] | null = await analyzeImage(source, priority, maxPoints);

Parameters:

  • source — HTMLImageElement, HTMLCanvasElement, or ImageBitmap
  • priority — 0 (visible) | 1 (preload) | 2 (background, default)
  • maxPoints — Number of focal points to find (1 = default, 2-10 recommended)

Methods:

  • cancelAnalysis() — Cancel current or queued task
  • updatePriority(newPriority) — Upgrade priority of queued task
  • isReady — Whether WASM module is initialized

Component Behavior

  • Lazy Loading: Analysis starts when component enters viewport (uses Intersection Observer)
  • CORS Required: Remote images must have appropriate CORS headers
  • Memory Safe: Automatically cleans up WASM memory after analysis
  • Race Condition Safe: Discards results if image URL changes during analysis
  • Error Handling: Graceful fallback with error message if image fails to load
  • Debug Visualization: Shows all detected focal points with size scaled by confidence score

⚙️ Performance Comparison

| Task | JavaScript | WebAssembly | Speedup | |------|-----------|------------|----------| | Saliency Analysis (1 image) | ~450ms | ~15ms | 30x | | Grid Calculation | ~200ms | ~5ms | 40x | | Edge Detection | ~180ms | ~12ms | 15x |

Results on MacBook Pro M1, average of 100 iterations


�🔬 How It Works

Algorithm Overview

  1. Image Downsampling (64×64 px)

    • Reduces to standard size for consistent analysis
    • Canvas API used for efficient resizing
  2. Pixel Grid Analysis (20×20 regions)

    • Divides image into 400 regions
    • Each region scored for importance
  3. Saliency Scoring

    • Edge detection using gradient analysis
    • Color distribution measurement
    • Center-bias weighting (favors compositionally balanced points)
    • Skin tone analysis for portrait photos
  4. Max Pooling

    • Identifies most important 3×3 region cluster
    • Smooths out noise
  5. Focal Point Calculation

    • Converts region coordinates to pixel percentages
    • Applied via CSS object-position for responsive cropping

Data Flow Architecture

┌─────────────────────────────────────────────────────────┐
│                     BROWSER (CLIENT)                    │
├─────────────────────────────────────────────────────────┤
│                                                         │
│  ┌──────────────┐         ┌───────────────┐             │
│  │   Image URL  │────────>│  Intersection │             │
│  │  (CORS Safe) │         │    Observer   │             │
│  └──────────────┘         │  (Lazy Load)  │             │
│                           └───────────────┘             │
│                                  │                      │
│                                  ▼                      │
│                         ┌──────────────────┐            │
│                         │  Canvas 2D API   │            │
│                         │  (64×64 resize)  │            │
│                         └──────────────────┘            │
│                                  │                      │
│                                  ▼                      │
│                    ╔══════════════════════╗             │
│                    ║   WASM MODULE        ║             │
│                    ║  (C++ Compiled)      ║             │
│                    ║                      ║             │
│                    ║  ✓ Edge Detection    ║             │
│                    ║  ✓ Saliency Analysis ║             │
│                    ║  ✓ Max Pooling       ║             │
│                    ║  ✓ Focal Point Calc  ║             │
│                    ╚══════════════════════╝             │
│                                  │                      │
│                                  ▼                      │
│                    ┌──────────────────────┐             │
│                    │ Result Object        │             │
│                    │ { x: 45, y: 60 }     │             │
│                    │ (percentages)        │             │
│                    └──────────────────────┘             │
│                                  │                      │
│                                  ▼                      │
│              ┌──────────────────────────────┐           │
│              │  CSS object-position Apply   │           │
│              │  object-position: 45% 60%    │           │
│              └──────────────────────────────┘           │
│                                  │                      │
│                                  ▼                      │
│                    ┌──────────────────────┐             │
│                    │  Focused Image       │             │
│                    │  Rendered on Screen  │             │
│                    └──────────────────────┘             │
│                                                         │
└─────────────────────────────────────────────────────────┘

Key Points:

  • 100% Client-Side — No server communication
  • Non-Destructive — Uses CSS, original image unmodified
  • Memory Safe — Automatic cleanup after analysis
  • Privacy — Image data never leaves your browser

Architecture

React Component (SmartCropImage)
    ↓
JavaScript Hook (useSmartCrop)
    ↓
WASM Module (C++ compiled)
    ↓
Canvas API (pixel data)
    ↓
Result: { x: %, y: % }

Key Technologies:

  • Emscripten: C++ to WASM compiler toolchain
  • Canvas API: Pixel data extraction
  • Intersection Observer: Lazy loading optimization
  • CSS object-position: Non-destructive cropping
  • WASM Memory: Manual malloc/free for performance

🐛 Troubleshooting & Caveats

CORS Issues

Problem: Image won't load or analysis fails with cross-origin images

Solution: Ensure the image server includes CORS headers:

Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: GET, HEAD, OPTIONS

On your own server (Node/Express example):

app.use((req, res, next) => {
  res.header('Access-Control-Allow-Origin', '*');
  next();
});

Pass crossOrigin="anonymous" if needed (handled automatically by component).

WASM Not Supported

Problem: Console error about WebAssembly not being available

Solution: Check browser support or add fallback:

import { SmartCropImage } from '@sargis-artashyan/react-smart-crop';

export function Image({ src, alt }) {
  const hasWasm = typeof WebAssembly !== 'undefined';
  
  if (!hasWasm) {
    return <img src={src} alt={alt} />;  // Fallback to default
  }
  
  return <SmartCropImage src={src} alt={alt} />;
}

Performance on Mobile

Issue: Analysis slow on lower-end devices

Tips:

  • Use debug mode sparingly (adds rendering overhead)
  • Lazy loading is enabled by default (respects viewport)
  • Image downsampling is aggressive (64×64) for performance
  • WASM memory is automatically freed after analysis

Memory Leaks

Handled by default: The hook automatically calls module._free(ptr) after each analysis. No manual cleanup needed.

Black/Blank Canvas

Problem: Canvas context returns null

Solution: Ensure images are loaded and have valid dimensions:

<SmartCropImage
  src={validUrl}  // Not null/undefined
  width={300}      // Must be > 0
  height={300}     // Must be > 0
/>

� Social Proof

If this project has helped you build better UIs, please consider giving it a star! ⭐

Your support helps us:

  • 📈 Reach more developers
  • 🚀 Continue improving the library
  • 💪 Build confidence in the community

| Browser | Minimum Version | WASM Support | Status | |---------|-----------------|--------------|--------| | Chrome | 74+ | ✅ Full | Fully Supported | | Firefox | 79+ | ✅ Full | Fully Supported | | Safari | 14.1+ | ✅ Full | Fully Supported | | Edge | 79+ | ✅ Full | Fully Supported | | Opera | 61+ | ✅ Full | Fully Supported | | iOS Safari | 14.5+ | ✅ Full | Fully Supported | | Android Chrome | 74+ | ✅ Full | Fully Supported |

WebAssembly Support: Visit caniuse.com/wasm for detailed compatibility.

Fallback Strategy: Detect WASM and fall back to default image rendering if unavailable.


Known Limitations

  • Single focal point per image (not multiple regions)
  • Requires CORS-enabled image sources
  • Downsamples large images to 64×64 (by design, for performance)
  • Best results with properly exposed, well-lit photos

📄 License & Attribution

License: MIT © 2026

Author: Sargis Artashyan
Location: 🏔️ Gyumri, Armenia

Credits

  • Algorithm: Saliency detection inspired by computer vision research
  • Implementation: C++ with Emscripten toolchain
  • Testing: Made possible by Unsplash photographers

Demo Images Attribution


🤝 Contributing

We welcome contributions! Please:

  1. Fork the repository
  2. Create a feature branch (git checkout -b feature/amazing-feature)
  3. Commit changes (git commit -m 'Add amazing feature')
  4. Push to branch (git push origin feature/amazing-feature)
  5. Open a Pull Request

Development Setup

# Clone repository
git clone https://github.com/sargisartashyanmain/react-smart-crop.git
cd react-smart-crop

# Install dependencies
npm install

# Build WASM module (requires Emscripten)
./scripts/build-wasm.sh

# Start dev server
npm run dev

# Build library
npm run build

# Run linter
npm run lint

📞 Support & Questions


📊 Performance Metrics

  • Analysis Time: ~50-200ms per image (depending on device)
  • Bundle Size: ~45KB (minified + gzipped)
  • WASM Module: ~35KB
  • Memory Usage: ~2-5MB peak (cleaned up after analysis)
  • Speedup: 20-30x faster than JavaScript implementation

Made with ❤️ in Armenia