Skip to content

dragidavid/aura

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

aura

Grab colors from any image.
Works on both server and client, supporting remote URLs, local files, and raw image data.

NPM version License

hero

Installation

To get started, install the required dependencies:

pnpm add @drgd/aura sharp

Server-side usage requires the peer dependency sharp to be installed as shown above.

Usage

Import the desired function/hook from the appropriate entry point.

Client-side

Use the useAura hook to extract colors on the client. It accepts a remote image URL or a local static path (e.g., from your public folder).

Example with an image URL or local path:

"use client";

import { useAura } from "@drgd/aura/client";

export function Colors({ imagePath }: { imagePath: string }) {
  // e.g., "/assets/my-image.webp" or "https://picsum.photos/200"
  const { colors, isLoading, error } = useAura(imagePath, {
    paletteSize: 4, // Optional: Specify number of colors (1-12, default: 6)
    onError: (err) => console.error(err.message), // Optional: Error callback
  });

  if (isLoading) return <p>Loading...</p>;

  if (error) return <p>Error: {error.message}</p>;

  // On error, 'colors' will contain the fallback palette
  return (
    <ul className>
      {colors.map((color) => (
        <li
          key={color.hex}
          style={{
            backgroundColor: color.hex,
          }}
        >
          {color.hex} -{Math.round(color.weight * 100)}%
        </li>
      ))}
    </ul>
  );
}

Server-side

Use the getAura function inside an async Server Component. It accepts a remote image URL or a Buffer. To prevent blocking the initial page load while the colors are being extracted, wrap the getAura call in <Suspense>.

We use sharp under the hood to process the image. Check out the sharp β†— documentation for more information.

Example with an image URL:

import { Suspense } from "react";
import { getAura } from "@drgd/aura/server";

// Server Component that gets the colors
async function Colors({ imageUrl }: { imageUrl: string }) {
  const colors = await getAura(imageUrl, {
    paletteSize: 8, // Optional: Specify number of colors (1-12, default: 6)
    // quality: 'high', // Optional: 'low' (200px), 'medium' (400px), 'high' (800px)
    // timeout: 5000, // Optional: Max processing time in ms (default: 10000)
    // validateUrl: false, // Optional: Disable internal URL checks (default: true)
    // fallbackColors: [{ hex: '#...', weight: 1 }], // Optional: Custom fallbacks
  });

  return (
    <ul>
      {colors.map((color) => (
        <li key={color.hex} style={{ backgroundColor: color.hex }}>
          {color.hex} - {Math.round(color.weight * 100)}%
        </li>
      ))}
    </ul>
  );
}

// Parent Server Component
export default async function Page() {
  const imageUrl = "https://picsum.photos/200";

  return (
    <div>
      <h1>Image Colors</h1>
      <Suspense fallback={<p>Loading colors...</p>}>
        <Colors imageUrl={imageUrl} />
      </Suspense>
    </div>
  );
}

Example with a local image Buffer:

import fs from "fs";
import path from "path";
import { Suspense } from "react";
import { getAura } from "@drgd/aura/server";

// Server Component that gets the colors
async function LocalColors({ imageFileName }: { imageFileName: string }) {
  // Construct the full path to the image in your public directory or elsewhere
  const imagePath = path.join(process.cwd(), "public", "assets", imageFileName);
  let colors;

  try {
    const imageBuffer = await fs.readFile(imagePath);

    colors = await getAura(imageBuffer, { paletteSize: 8 });
  } catch (error) {
    console.error("Failed to process image", error);

    // getAura returns fallback colors on processing errors, but file read might fail
    colors = await getAura(Buffer.from(""), { paletteSize: 5 });
  }

  return (
    <ul>
      {colors.map((color) => (
        <li key={color.hex} style={{ backgroundColor: color.hex }}>
          {color.hex} - {Math.round(color.weight * 100)}%
        </li>
      ))}
    </ul>
  );
}

// Parent Server Component
export default async function Page() {
  return (
    <div>
      <h1>Local Image Colors</h1>
      <Suspense fallback={<p>Loading colors...</p>}>
        <LocalColors imageFileName="/assets/1.webp" />
      </Suspense>
    </div>
  );
}

API Reference

useAura(imageUrl, options?) (Client)

React hook for client-side color extraction.

Parameters

  • imageUrl?: string | null
    • URL of the image or a local static path
    • Uses default fallbackColors if not provided
  • options?: object
    • paletteSize?: number - Number of colors to extract (default: 6, range: 1-12)
    • fallbackColors?: AuraColor[] - Custom fallback colors array
    • onError?: (error: Error) => void - Error callback function

Returns

  • colors: AuraColor[] - Array of extracted (or fallback) colors, sorted by weight
  • isLoading: boolean - Boolean indicating extraction status
  • error: Error | null - Error object if failed, null otherwise

getAura(imageUrlOrBuffer, options?) (Server)

Async function for server-side color extraction.

Parameters

  • imageUrlOrBuffer: string | Buffer - The URL of the image or a Buffer containing image data
  • options?: object
    • paletteSize?: number - Number of colors to extract (default: 6, range: 1-12)
    • quality?: "low" | "medium" | "high" - "low" (200px) | "medium" (400px) | "high" (800px)
    • timeout?: number - Maximum processing time in milliseconds (default: 10000)
    • fallbackColors?: AuraColor[] - Custom fallback colors array
    • validateUrl?: boolean - Whether to perform internal URL validation checks (protocol, type, size). Recommended to leave enabled unless URLs are pre-validated (default: true)

Returns

A promise resolving to the array of extracted (or fallback) colors, sorted by weight. Throws an error only for invalid paletteSize. Other errors (network, processing) result in fallback colors being returned.

AuraColor type

type AuraColor = {
  hex: string; // Hexadecimal color code (e.g., "#FF0000")
  weight: number; // Color prevalence/importance (0-1)
};

Error Handling

Both implementations include built-in error handling with fallback colors:

  • Invalid image URLs
  • Network errors
  • Timeout errors (10s default)
  • Invalid image data
  • CORS errors

Authors

License

MIT License.