huerd (development version)
Bug Fixes
-
plot_palette_analysis()no longer advances the global random number generator state: the point jitter of the comparative panels is now drawn underwithr::with_preserve_seed(), so rendering a dashboard no longer silently changes downstream random results -
plot_palette_analysis()now treats an OKLAB matrix input like the equivalent hex vector: the reference-palette panel selects by color count instead oflength()of the matrix (3 cells per color previously pushed 3+ color matrices into the large-palette branch), and a single-row matrix now returns early like a single hex color. Undetermined (NA) pairwise distances render as neutral grey cells in the distance heatmap instead of transparent ones
Improvements
- The pairwise distance heatmap of the
plot_palette_analysis()dashboard now colors cells on a fixed scale (from the distinctness threshold to the theoretical maximum OKLAB distance of ~1.0) instead of normalizing to each palette’s own maximum; cell colors now encode absolute distances and are directly comparable across palettes and dashboards - The dashboard panel descriptions in the “Introduction to huerd” vignette now match the actual panels (the long-removed “Nearest Neighbor Distances” panel is no longer listed, and the two boxplot panels are described)
-
is_cvd_safe()’smin_cvd_distancedefault now derives from the package-wide distinctness threshold constant instead of a duplicated0.08literal, so the two can no longer drift apart silently (default value unchanged) - The
DESCRIPTIONTitleis now in title case, resolving anR CMD check --as-cranNOTE
Deprecated
-
optimizer = "nlopt_direct"ingenerate_palette()is now deprecated and emits a warning; it will be removed in a future release. The DIRECT algorithm’s center-lattice sampling cannot reliably find configurations with all pairwise-separated colors in this parameterization, so it returns degenerate palettes (all colors collapsing to a single hex) for most palette sizes; increasingmax_iterationsdoes not help. Use the default"nloptr_cobyla"or"nlopt_neldermead"instead.
Internal Changes
- Removed more dead internal code and doc drift: the unused
.calculate_luminance()helper and the emptyR/data.R; the text-only color print helper is renamed.print_color_with_swatch()->.print_color_label()and its roxygen (plusprint_color_vector()’s) no longer claims swatches;.handle_no_free_colors()roxygen documentsgeneration_metadataand drops the nonexistentoptimize_for -
initialize_kmeans_plus_plus()candidate-center distance computation vectorized: the nestedapply()loops over candidates and centers are replaced by a per-centerrowSums()/pmin()accumulation. Results are bit-identical (verified withidentical()across 80 seed x configuration combinations and at thegenerate_palette()level), with a large speedup for palettes with many free colors: then_free = 100tests drop thehelpers-initfile from ~224 s to ~4 s - Test suite pruned of non-behavioral slop: 65 tests removed (function-existence and
formals()signature checks,requireNamespace()-style dependency checks, constant/export existence assertions, and a “gamut penalty” test that re-implemented arithmetic from an implementation that no longer exists); no behavioral coverage lost. The.merge_aesthetic_config()version-mismatch snapshot now records an input reachable through the public API (config_version = 999) instead of a string version and an unknown key, both of whichvalidate_inputs()rejects before the merge ever sees them - Deduplicated the five optimizer implementations (
optimize_colors_constrained(),optimize_colors_sann(),optimize_colors_nlopt_direct(),optimize_colors_nlopt_neldermead(),optimize_colors_lbfgs()) into a single shared internal driver; roughly 1,000 lines removed with no behavior change (verified byte-identical outputs across all optimizers) - Removed the unreachable optimization-state-tracking machinery: the
track_states,save_every, andreturn_statesparameters of the optimizers and the correspondingoptimization_statesplumbing; no public API or caller ever used them - Removed dead internal code: the unused
validate_color_input_smart()/validate_hex_colors()/validate_oklab_matrix()validation subsystem, the legacy multi-objectiveobjective_function_aggregator(), the unused.validate_balance_weights(),.validate_aesthetic_weights(), and.normalize_weights()helpers, and the unusedtrack-free print indirection.print_color_item() - Removed three
aesthetic_init_configkeys that were accepted but never used by any code (kmeans_C_sd_multiplier,harmony_hcl_L_min_sd,harmony_hcl_C_min_sd); passing them now errors with an “Invalid name” message instead of being silently ignored - Cleaned unused NAMESPACE imports (
colorspace::simulate_cvd,stats::setNames,stats::var,grDevices::rgb) - Removed all redundant NAMESPACE
importFromdirectives (every call site uses explicitpkg::qualification); the last two unqualified calls (dist(),hcl.colors()) were namespace-qualified
huerd 0.6.2 (2026-08-16)
Bug Fixes
-
interpret_palette_quality()no longer errors on palettes with more than 40 colors, where the theoretical-maximum distance lookup is undefined andperformance_ratioisNA; the summary now reports that the percentage is not available -
validate_color_input_smart()now reports the actual problem (“Colors must be a character vector (hex codes) or an OKLAB matrix”) for wrong-type inputs instead of an unrelated “no base colors provided” message -
export_palette()documentation now correctly states that"hex"returns a character vector, not a single string
New Features
-
generate_palette()gains acvd_safeargument (defaultTRUE): whenTRUE, the objective maximizes the worst-case perceptual distance across deuteranopia, protanopia, and tritanopia simulations; whenFALSE, it optimizes normal-vision distance only. Applies to all derivative-free optimizers; documented as having no effect for"nlopt_lbfgs", whose smooth objectives are normal-vision only - The previously ignored
cvd_safearguments ofquick_palette()andbrand_palette()are now forwarded togenerate_palette()and take effect -
reproduce_palette()forwards the storedcvd_safesetting; palettes generated before 0.6.2 reproduce with the previous default behavior
Infrastructure
- Moved
withrfrom Suggests to Imports:reproduce_palette()callswithr::with_preserve_seed()on its default code path, which must not fail for installations without suggested packages - Removed the committed
R/.tldrtool cache from version control (already excluded from the built tarball via.Rbuildignore) - Removed redundant
Author/Maintainerfields fromDESCRIPTION(regenerated automatically fromAuthors@R)
huerd 0.6.1 (2026-01-26)
Bug Fixes
-
plot_palette_analysis()now returnsinvisible(NULL)without warning when fewer than two colors are supplied. -
simulate_palette_cvd()returns empty results silently when input contains no valid colors. -
plot_cvd_comparison()now preserves the fallback border color when color conversion fails. - Optimizers validate inputs and return structured results instead of failing on invalid inputs (
optimize_colors_constrained(),optimize_colors_sann()).
huerd 0.6.0 (2026-01-18)
Bug Fixes
- Fixed hex color validation regex in
evaluate_palette()to properly reject literal “NA” strings while allowing actual NA values - Fixed flaky test in
test-optimization-core.Rfor nlopt_neldermead optimizer performance expectations - Fixed
reproduce_palette()to properly restore RNG state usingwithr::with_preserve_seed()instead of direct.Random.seedmanipulation - Fixed
validate_oklab_matrix()test errors by properly initializing validation_result structure
Code Quality Improvements
- Added comprehensive documentation to internal helper functions with @param descriptions
- Improved error handling and validation in
export_palette()for different export formats (JSON, CSV, CSS, Sass) - Enhanced L-BFGS optimizer state consistency by adding
colors_oklabfield and defensive clamping - Updated all tests to use testthat 3rd edition describe/it BDD pattern (1,006+ tests)
- Fixed CVD analysis tests to handle list structure return from
simulate_palette_cvd()
New Features
- Added
quick_palette()for one-line palette generation - Added
brand_palette()for brand color integration - Added
export_palette()with support for JSON, CSV, CSS, and Sass formats - Added
interpret_palette_quality()for palette quality assessment - Added
plot.huerd_palette()method with “swatches” and “analysis” plot types - Added ggplot2 integration:
scale_color_huerd(),scale_fill_huerd(),scale_colour_huerd()
huerd 0.5.3
Breaking Changes
-
simulate_palette_cvd()with a singlecvd_typenow returns a named list instead of a character vector; access the simulated colors viaresult$simulated. The print method was updated accordingly
Code Quality Improvements
This release focuses on code quality, maintainability, and consistency improvements identified through comprehensive code review.
User Messaging
- Replaced
cat()calls with semanticclimessaging functions (cli_alert_info(),cli_alert_warning(),cli_alert_success(),cli_inform()) for better user experience - Added
clito package Imports
Code Organization
- Added named constants for magic numbers:
.CANDIDATE_POOL_BASE,.MIN_DISTANCE_THRESHOLD,.OKLAB_TOLERANCE - Extracted repeated clamping code to
.clamp_to_bounds()helper function - Added
@paramdocumentation to internal helper functions - Removed dead/commented-out code
API Consistency
- Added
...parameter to exported functions for future extensibility -
simulate_palette_cvd()return structure unified across single and multiplecvd_typevalues (see Breaking Changes above)
huerd 0.5.2 (2025-07-21)
Bug Fixes
- Corrected distance matrix calculation in smooth optimization objectives where diagonal masking affected only element [1,1] rather than the full diagonal
- Eliminated redundant distance calculations by using
dist()output directly instead of symmetric matrix conversion - Applied log-sum-exp numerical stability technique for robust computation under extreme parameter values
- Added regression tests for distance calculation correctness
huerd 0.5.0 (2025-07-07)
New Features
API Changes
- Added
optimizer = "nlopt_lbfgs"option for L-BFGS optimization - Added
weights = c(smooth_repulsion = 1)andweights = c(smooth_logsumexp = 1)for smooth objectives
Bug Fixes
- Fixed critical bug where L-BFGS optimizer always used
smooth_repulsionobjective regardless ofweightsparameter - Fixed crash in
evaluate_palette_quality()when called directly with hex colors (“argument is of length zero” error) - Both smooth objectives (
smooth_repulsionandsmooth_logsumexp) now work correctly and produce different optimization results
huerd 0.4.2 (2025-07-07)
huerd 0.4.0 (2025-07-06)
Major Changes
Replaced base R graphics with grid graphics system.
plot_palette_analysis()now usesgridExtra::arrangeGrob()for layout.Converted all plotting functions to return grob objects instead of drawing directly.
New Features
Added reproducibility system for palette generation with metadata storage.
Added hue order reversal detection for CVD analysis.
Breaking Changes
Removed
new_device,device_width, anddevice_heightparameters fromplot_palette_analysis().Moved
gridExtrafrom Suggests to Imports, addedgridto Imports.Removed helper functions:
.create_graphics_device,.is_ragg_available,.is_interactive_ide,calculate_safe_margins.
huerd 0.3.1 (2025-07-04)
New Features
- Added automated font size scaling to
plot_palette_analysis()that automatically adjusts text sizes based on device dimensions.
huerd 0.3.0 (2025-07-04)
Major Changes
- Multi-optimizer framework: The
generate_palette()function now supports four different optimization algorithms through the newoptimizerparameter:-
"nloptr_cobyla"(default): Deterministic optimization with constraint handling -
"sann": Stochastic simulated annealing -
"nlopt_direct": Deterministic global optimization using DIRECT algorithm -
"nlopt_neldermead": Derivative-free local optimization using Nelder-Mead simplex
-
- Added automatic font scaling to
plot_palette_analysis()that prevents text overlap and out-of-frame issues.
huerd 0.1.0 (2025-07-01)
This is a major refactoring and simplification of huerd, focusing the package on a single, scientifically-grounded objective: pure minimax color palette generation.
Major Changes
Pure minimax optimization: The core
generate_palette()function has been streamlined to use a pure minimax objective, maximizing the minimum perceptual distance between colors in the OKLAB space. All complex multi-objective parameters (optimize_for,balance_weights,aesthetic_penalty_weights_LC) have been removed, simplifying the API and aligning the package with a clear, defensible scientific goal.Comprehensive diagnostic dashboard: A new
plot_palette_analysis()function has been added. It provides a comprehensive, six-panel diagnostic dashboard inspired byscicomapfor in-depth palette analysis. This feature uses only base R graphics and introduces zero new dependencies.Automatic brightness sorting: All palettes generated by
generate_palette()are now automatically sorted by their OKLAB lightness value, ensuring intuitive and consistent ordering from darkest to lightest.Simplified evaluation: The
evaluate_palette()function is now a pure data provider, returning raw, objective metrics (distances, CVD safety, color distribution) without any subjective heuristic scoring.
Minor Changes
- The
is_cvd_safe()function now uses the more robustevaluate_palette()function for its calculations. - The print methods for
huerd_paletteandhuerd_evaluationhave been updated to reflect the new, simplified data structures.
Removals
The following experimental and non-essential features have been removed to streamline the package:
- Force-field and repulsion-based optimization algorithms.
- Palette animation framework.
- Algorithm comparison tools.
- Post-hoc CVD refinement steps.
- 3D color space visualizations.
- All functionality related to the CAM16 and CIECAM16 color models.
huerd 0.0.3 (2025-06-22)
- Added a post-hoc
cvd_adjustmentstep to improve palettes for color vision deficiency. - Added a
README.mdwith basic usage instructions.
