daikazu / laratone
Simple API for managing color libraries in you Laravel application.
Fund package maintenance!
Requires
- php: ^8.3
- illuminate/contracts: ^12.0|^13.0
- illuminate/support: ^12.0|^13.0
Requires (Dev)
- larastan/larastan: ^3.0
- laravel/pint: ^1.18
- nunomaduro/collision: ^8.5
- orchestra/testbench: ^10.0|^11.0
- pestphp/pest: ^3.0|^4.0|^5.0
- pestphp/pest-plugin-arch: ^3.0|^4.0|^5.0
- pestphp/pest-plugin-laravel: ^3.0|^4.0|^5.0
- phpstan/extension-installer: ^1.4
- phpstan/phpstan-deprecation-rules: ^2.0
- phpstan/phpstan-phpunit: ^2.0
- rector/rector: ^2.0
- tightenco/duster: ^3.2
Suggests
None
Provides
None
Conflicts
None
Replaces
None
This package is auto-updated.
Last update: 2026-10-07 16:34:52 UTC
README
Laratone
Laratone is a comprehensive Laravel package for managing color libraries and swatches in your applications. It provides an easy-to-use API for storing, retrieving, and managing color data, with built-in support for various color formats (HEX, RGB, CMYK, LAB, OKLCH) and popular color libraries.
Features
- Multiple built-in color libraries (Solid Coated, GuangShun Thread, HC Twill)
- Auto-calculation of RGB, CMYK, LAB, and OKLCH from hex values
- Find closest matching colors in one color book or across all of them, using CIE76 (LAB), CIEDE2000 or OKLCH distance
- Search colors by name or code (e.g.
185 C) - Configurable white point reference for LAB color calculations
- Automatic color data caching with configurable TTL
- Easy color book management and seeding
- Flexible REST API with filtering, sorting, and pagination (configurable prefix, or turn it off entirely)
- Type-safe color value casting (LAB, RGB, CMYK, OKLCH)
- PHP 8.3+ support with strict typing throughout
Requirements
- PHP 8.3 or higher
- Laravel 12.x or 13.x
Note: For Laravel 11 support, use version 4.x of this package.
Installation
You can install the package via composer:
composer require daikazu/laratone
Publish Configuration and Migrations
Publish the configuration file:
php artisan vendor:publish --tag="laratone-config"
Publish and run the migrations:
php artisan vendor:publish --tag="laratone-migrations"
php artisan migrate
Configuration
The published config file (config/laratone.php) contains the following options:
return [ // Table prefix for Laratone tables 'table_prefix' => 'laratone_', // Cache duration in seconds for color books and colors 'cache_time' => 3600, // Reference white point for LAB color calculations // Options: 'D50' (print), 'D55', 'D65' (daylight, default), 'D75' 'white_point' => 'D65', // Store calculated RGB/CMYK/LAB/OKLCH values when saving a color 'pre_calculate_colors' => false, // Default algorithm for finding closest colors: 'lab', 'ciede2000' or 'oklch' 'default_match_algorithm' => 'lab', // Maximum number of colors that find-closest and search can return 'max_match_limit' => 100, // API rate limit as "maxAttempts,decayMinutes" (null to disable) 'rate_limit' => '60,1', // REST API routes: turn them off, or change the URL prefix 'routes' => [ 'enabled' => true, 'prefix' => 'api/laratone', ], ];
White Point Options
When RGB, CMYK, LAB, or OKLCH values are not provided, they are automatically calculated from the hex value. LAB calculations require a reference white point (illuminant). OKLCH is a perceptually uniform color space and does not require white point configuration.
| Value | Description | Use Case |
|---|---|---|
D50 |
Warm white (~5000K) | Print/graphic arts |
D55 |
Mid-morning daylight (~5500K) | Photography |
D65 |
Standard daylight (~6500K) | Default, web/screen |
D75 |
North sky daylight (~7500K) | Scientific applications |
Checking Your Setup
Laratone adds a section to Laravel's about command showing the installed version and key settings:
php artisan about --only=laratone
Laratone ....................................................................
Match Algorithm ......................................................... lab
Pre-calculate Colors .................................................... OFF
Rate Limit ............................................................. 60,1
Table Prefix ...................................................... laratone_
Version ............................................................... 5.2.0
White Point ............................................................. D65
Usage
Seeding Color Books
Laratone comes with several pre-built color libraries:
ColorBookPlusSolidCoatedColorBookPlusSolidCoated336NewColorsColorBookMetallicCoatedColorBookPlusMetallicCoatedGuangShunThreadColorsHCTwillColors
Seed All Color Books
php artisan laratone:seed
Seed Specific Color Books
php artisan laratone:seed ColorBookPlusSolidCoatedSeeder
Import Custom Color Books
php artisan laratone:seed --file ./mycolorbookfile.json
Example Color Book format:
{
"name": "My Custom Color Book",
"data": [
{
"name": "Custom Color 1",
"hex": "FEDD00"
},
{
"name": "Custom Color 2",
"hex": "FF5500",
"lab": "88.19,-6.97,111.73",
"rgb": "254,221,0",
"cmyk": "0,1,100,0",
"oklch": "0.7206,0.1654,56.72"
}
]
}
Note: Only
nameandhexare required. RGB, CMYK, LAB, and OKLCH values are optional and will be auto-calculated from hex if not provided. If you have official color values (e.g., Solid Coated LAB values), include them to use those instead of calculated values.
REST API
All endpoints live under /api/laratone by default. Change the prefix, or turn the routes off entirely if you only use the facade:
// config/laratone.php 'routes' => [ 'enabled' => true, // false = don't register any Laratone routes 'prefix' => 'colors/v1', // endpoints become /colors/v1/colorbooks, ... ],
Route names (laratone.colorbooks, laratone.colorbook, laratone.colorbook.search, laratone.colorbook.find-closest, laratone.find-closest) stay the same whatever the prefix, so route() calls keep working.
Color Books
List all available color books:
GET /api/laratone/colorbooks
| Parameter | Required | Description | Default |
|---|---|---|---|
| sort | No | Sort by name (asc/desc) | - |
Colors
Get colors from a specific color book:
GET /api/laratone/colorbook/{slug}
| Parameter | Required | Description | Default |
|---|---|---|---|
| sort | No | Sort by name (asc/desc) | - |
| limit | No | Limit number of results | - |
| random | No | Randomize results (1/true) | false |
Note: When using
random=true, results are not cached to ensure different results on each request.
Search Colors
Search a color book's colors by name or code. Matching is case-insensitive and finds the text anywhere in the name:
GET /api/laratone/colorbook/{slug}/search
| Parameter | Required | Description | Default |
|---|---|---|---|
| q | Yes | Text to search for in color names (max 100 chars) | - |
| limit | No | Maximum number of results (up to max_match_limit) |
25 |
Example Request:
GET /api/laratone/colorbook/color-book-plus-solid-coated/search?q=185
Example Response:
{
"query": "185",
"matches": [
{
"name": "185 C",
"hex": "E4002B",
"rgb": {"r": 228, "g": 0, "b": 43},
"cmyk": {"c": 0, "m": 93, "y": 79, "k": 0},
"lab": {"l": 47.41, "a": 75.29, "b": 44.4},
"oklch": {"l": 0.5794, "c": 0.2343, "h": 23.93}
}
]
}
Results are ordered by name. This example is trimmed to one match; the full response also includes 2185 C and 5185 C.
Find Closest Colors
Find the closest matching colors in a color book to a target color:
GET /api/laratone/colorbook/{slug}/find-closest
| Parameter | Required | Description | Default |
|---|---|---|---|
| hex | Yes | Target color (6-char hex, with or without #) | - |
| limit | No | Number of closest colors to return | 1 |
| algorithm | No | Distance algorithm: lab, ciede2000 or oklch |
default_match_algorithm (lab) |
Example Request:
GET /api/laratone/colorbook/color-book-plus-solid-coated/find-closest?hex=FF5500&limit=1&algorithm=lab
Example Response:
{
"target_hex": "FF5500",
"algorithm": "lab",
"matches": [
{
"name": "1655 C",
"hex": "FC4C02",
"distance": 3.2986,
"rgb": {"r": 252, "g": 76, "b": 2},
"cmyk": {"c": 0, "m": 73, "y": 98, "k": 0},
"lab": {"l": 57.92, "a": 64.35, "b": 68.37},
"oklch": {"l": 0.6618, "c": 0.2214, "h": 36.88}
}
]
}
Find Closest Colors Across All Books
Find the closest matches to a target color in every color book at once, for example to see which ink or thread library has the nearest match:
GET /api/laratone/find-closest
Takes the same hex, limit and algorithm parameters as the single-book endpoint. Each match includes the color book it came from. Here, ?hex=FF5500&algorithm=ciede2000 finds the same Solid Coated color, scored with CIEDE2000:
{
"target_hex": "FF5500",
"algorithm": "ciede2000",
"matches": [
{
"color_book": {"name": "Color Book Plus Solid Coated", "slug": "color-book-plus-solid-coated"},
"name": "1655 C",
"hex": "FC4C02",
"distance": 2.1238,
"rgb": {"r": 252, "g": 76, "b": 2},
"cmyk": {"c": 0, "m": 73, "y": 98, "k": 0},
"lab": {"l": 57.92, "a": 64.35, "b": 68.37},
"oklch": {"l": 0.6618, "c": 0.2214, "h": 36.88}
}
]
}
Distance Algorithms
| Algorithm | Description | Best For |
|---|---|---|
lab |
CIE76 Delta E: straight-line distance in LAB space | Fast general matching (the default) |
ciede2000 |
CIEDE2000 Delta E: corrects CIE76's errors with saturated colors and blues | Print, ink and textile matching, the industry standard |
oklch |
Distance in the OKLab color space | Modern screen colors, consistent perception |
Distances aren't comparable between algorithms. For CIE76 and CIEDE2000, a distance under about 1 is barely visible and under 2–3 is a close match. OKLCH distances are on a much smaller scale.
Rate Limiting & Custom Middleware
Laratone routes are rate limited to 60 requests per minute by default. Configure this with the rate_limit option (throttle middleware format, "maxAttempts,decayMinutes"):
// config/laratone.php 'rate_limit' => '120,1', // 120 requests per minute 'rate_limit' => null, // disable the built-in throttle
Routes also pass through a laratone middleware alias that does nothing by default. You can replace it with your own middleware to add authentication, logging, or a custom rate limiter (set rate_limit to null to avoid double throttling).
Define the alias in a service provider:
// app/Providers/AppServiceProvider.php use Illuminate\Routing\Router; public function boot(Router $router): void { $router->aliasMiddleware('laratone', \App\Http\Middleware\YourCustomMiddleware::class); }
You can create a custom middleware class that combines multiple behaviors:
// app/Http/Middleware/LaratoneApiMiddleware.php namespace App\Http\Middleware; use Closure; use Illuminate\Routing\Middleware\ThrottleRequests; class LaratoneApiMiddleware extends ThrottleRequests { public function handle($request, Closure $next, $maxAttempts = 60, $decayMinutes = 1, $prefix = '') { // Add custom logic here (authentication, logging, etc.) return parent::handle($request, $next, $maxAttempts, $decayMinutes, $prefix); } }
Programmatic Usage
Laratone provides a simple API for managing colors programmatically:
use Daikazu\Laratone\Facades\Laratone; // Get all color books with colors $colorBooks = Laratone::colorBooks(); // Get a specific color book by slug $colorBook = Laratone::colorBookBySlug('color-book-plus-solid-coated'); // Create a new color book $newColorBook = Laratone::createColorBook('My New Color Book'); // Create with custom slug $newColorBook = Laratone::createColorBook('My Color Book', 'custom-slug'); // Add a single color to a color book (only hex required) $color = Laratone::addColorToBook($colorBook, [ 'name' => 'New Color', 'hex' => 'FF0000', ]); // Or with explicit values (these take precedence over calculated values) $color = Laratone::addColorToBook($colorBook, [ 'name' => 'Solid Coated Red', 'hex' => 'FF0000', 'lab' => '53.23,80.11,67.22', // Official Solid Coated LAB value ]); // Add multiple colors at once $colors = Laratone::addColorsToBook($colorBook, [ ['name' => 'Red', 'hex' => 'FF0000'], ['name' => 'Green', 'hex' => '00FF00'], ['name' => 'Blue', 'hex' => '0000FF'], ]); // Get all colors from a color book $colors = Laratone::getColorsFromBook($colorBook); // Update a color Laratone::updateColor($color, ['name' => 'Updated Color Name']); // Delete a color Laratone::deleteColor($color); // Find closest matching colors to a target hex $closest = Laratone::findClosestColors($colorBook, 'FF5500'); // Returns the single closest color by default // Find multiple closest colors with specific algorithm $closest = Laratone::findClosestColors( colorBook: $colorBook, targetHex: 'FF5500', limit: 5, algorithm: 'ciede2000' // 'lab' (default), 'ciede2000' or 'oklch' ); // Each result includes a distance value foreach ($closest as $color) { echo "{$color->name}: {$color->distance}"; } // Find the closest colors across every color book $closest = Laratone::findClosestColorsInAllBooks('FF5500', limit: 3, algorithm: 'ciede2000'); foreach ($closest as $color) { echo "{$color->name} ({$color->colorBook->name}): {$color->distance}"; } // Search a color book by name or code (case-insensitive, partial match) $colors = Laratone::searchColors($colorBook, '185'); // up to 25 results $colors = Laratone::searchColors($colorBook, 'orange', 10); // custom limit // Calculate the CIEDE2000 difference between two LAB colors directly use Daikazu\Laratone\Services\ColorMatcher; $deltaE = app(ColorMatcher::class)->deltaE2000( ['l' => 50.0, 'a' => 2.6772, 'b' => -79.7751], ['l' => 50.0, 'a' => 0.0, 'b' => -82.7485], ); // 2.0425 // Clear cache manually Laratone::clearCache();
Working with Color Models
Color values are automatically cast to associative arrays when accessed. If a value wasn't stored in the database, it will be automatically calculated from the hex value:
use Daikazu\Laratone\Models\Color; $color = Color::first(); // Access color values as arrays $color->hex; // 'FF0000' (required, always stored) $color->rgb; // ['r' => 255, 'g' => 0, 'b' => 0] (stored or calculated) $color->lab; // ['l' => 53.23, 'a' => 80.11, 'b' => 67.22] (stored or calculated) $color->cmyk; // ['c' => 0, 'm' => 100, 'y' => 100, 'k' => 0] (stored or calculated) $color->oklch; // ['l' => 0.6279, 'c' => 0.2577, 'h' => 29.23] (stored or calculated) // Access the parent color book $colorBook = $color->colorBook;
Auto-Calculation Behavior
- Hex is required - All colors must have a hex value
- Other values are optional - RGB, CMYK, LAB, and OKLCH are calculated from hex if not provided
- Stored values take precedence - If you provide explicit values (e.g., official Solid Coated LAB), those are used instead of calculated values
- LAB uses white point config - Calculated LAB values use the
white_pointsetting from your config - OKLCH is perceptually uniform - OKLCH does not require white point configuration and provides consistent perceptual color representation
Caching
Laratone automatically caches color book and color data to improve performance. The cache works with any Laravel cache driver, including file, database, Redis, and Memcached.
Cache is automatically cleared when:
- Creating a new color book
- Adding, updating, or deleting colors
To manually clear the cache:
php artisan laratone:clear-cache
Or programmatically:
Laratone::clearCache();
AI Assistance (Laravel Boost)
Laratone ships Laravel Boost resources, so AI coding agents know how to use the package:
- Guideline (always loaded): an overview of the facade, models, color values and matching algorithms.
laratone-developmentskill: creating color books and colors, seeding, configuration, and the REST API.laratone-color-matchingskill: find-closest within a book or across all books, choosing an algorithm, reading distances, ΔE2000 and name search.
If your app uses Boost, they're picked up automatically when you run:
php artisan boost:install # or boost:update in an existing Boost setup
Upgrading
See UPGRADE.md for upgrade instructions between major versions.
Testing
composer test
Contributing
Please see CONTRIBUTING for details.
Security Vulnerabilities
Please review our security policy on how to report security vulnerabilities.
Credits
License
The MIT License (MIT). Please see License File for more information.