@basiclines/rampa-sdk 1.6.0 → 1.7.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +72 -21
- package/dist/index.d.ts +4 -3
- package/dist/index.js +56 -0
- package/dist/plane-color-space.d.ts +36 -0
- package/dist/types.d.ts +12 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -345,7 +345,11 @@ rampa('#3b82f6').size(5).lightness(10, 90).add('complementary').toJSON();
|
|
|
345
345
|
|
|
346
346
|
## Color Spaces
|
|
347
347
|
|
|
348
|
-
Color spaces let you create structured palettes from a set of anchor colors and query them semantically.
|
|
348
|
+
Color spaces let you create structured palettes from a set of anchor colors and query them semantically. Three geometric primitives are available:
|
|
349
|
+
|
|
350
|
+
- **LinearColorSpace** — 1D interpolated ramp
|
|
351
|
+
- **PlaneColorSpace** — 2D saturation×lightness plane
|
|
352
|
+
- **CubeColorSpace** — 3D trilinear interpolation cube
|
|
349
353
|
|
|
350
354
|
### `LinearColorSpace`
|
|
351
355
|
|
|
@@ -355,11 +359,9 @@ Interpolates between two colors to produce an evenly-spaced ramp.
|
|
|
355
359
|
import { LinearColorSpace } from '@basiclines/rampa-sdk';
|
|
356
360
|
|
|
357
361
|
const neutral = new LinearColorSpace('#ffffff', '#000000').size(24);
|
|
358
|
-
neutral(1) // →
|
|
359
|
-
neutral(12) // →
|
|
360
|
-
neutral(
|
|
361
|
-
neutral(12).hex // → '#666666'
|
|
362
|
-
neutral(12).format('hsl') // → 'hsl(0, 0%, 40%)'
|
|
362
|
+
neutral(1) // → '#ffffff' (lightest, returns string directly)
|
|
363
|
+
neutral(12) // → '#666666' (mid gray)
|
|
364
|
+
neutral(12).hsl() // → 'hsl(0, 0%, 40%)'
|
|
363
365
|
neutral.palette // → string[24]
|
|
364
366
|
```
|
|
365
367
|
|
|
@@ -377,6 +379,44 @@ base(1) // → '#45475a' (exact, no interpolation)
|
|
|
377
379
|
base(3) // → '#a6e3a1'
|
|
378
380
|
```
|
|
379
381
|
|
|
382
|
+
### `PlaneColorSpace`
|
|
383
|
+
|
|
384
|
+
Creates a 2D color plane for a single hue, anchored to shared dark/light values. Create one plane per hue.
|
|
385
|
+
|
|
386
|
+
```
|
|
387
|
+
Y(lightness)
|
|
388
|
+
1 │ light ─────────── hue
|
|
389
|
+
│ │ │
|
|
390
|
+
│ │ interpolated │
|
|
391
|
+
│ │ │
|
|
392
|
+
0 │ dark ─────────── dark
|
|
393
|
+
└──────────────────────── X(saturation)
|
|
394
|
+
0 1
|
|
395
|
+
```
|
|
396
|
+
|
|
397
|
+
At Y=0 the entire row converges to the dark anchor.
|
|
398
|
+
|
|
399
|
+
```typescript
|
|
400
|
+
import { PlaneColorSpace } from '@basiclines/rampa-sdk';
|
|
401
|
+
|
|
402
|
+
// One plane per hue, reuse dark/light anchors
|
|
403
|
+
const red = new PlaneColorSpace('#1e1e2e', '#cdd6f4', '#f38ba8').size(6);
|
|
404
|
+
const blue = new PlaneColorSpace('#1e1e2e', '#cdd6f4', '#89b4fa').size(6);
|
|
405
|
+
|
|
406
|
+
red(3, 5) // → ColorAccessor (saturation=3, lightness=5)
|
|
407
|
+
red(0, 3) // → achromatic at lightness 3 (no hue influence)
|
|
408
|
+
red(5, 5) // → full hue color
|
|
409
|
+
red(0, 0) // → dark anchor
|
|
410
|
+
red.palette // → string[36] (6²)
|
|
411
|
+
|
|
412
|
+
// Template literals and concatenation work directly
|
|
413
|
+
`background: ${red(3, 5)};` // → 'background: #ab34cd;'
|
|
414
|
+
|
|
415
|
+
// Format conversion
|
|
416
|
+
red(3, 5).hsl() // → 'hsl(280, 60%, 50%)'
|
|
417
|
+
red(3, 5).oklch() // → 'oklch(52.3% 0.198 310)'
|
|
418
|
+
```
|
|
419
|
+
|
|
380
420
|
### `CubeColorSpace`
|
|
381
421
|
|
|
382
422
|
Creates a 3D color cube from 8 corner colors via trilinear interpolation. The constructor keys become alias names for semantic lookups.
|
|
@@ -384,7 +424,7 @@ Creates a 3D color cube from 8 corner colors via trilinear interpolation. The co
|
|
|
384
424
|
```typescript
|
|
385
425
|
import { CubeColorSpace } from '@basiclines/rampa-sdk';
|
|
386
426
|
|
|
387
|
-
const tint = new CubeColorSpace({
|
|
427
|
+
const { r, b, tint } = new CubeColorSpace({
|
|
388
428
|
k: '#1e1e2e', // origin (0,0,0)
|
|
389
429
|
r: '#f38ba8', // x axis
|
|
390
430
|
g: '#a6e3a1', // y axis
|
|
@@ -395,11 +435,9 @@ const tint = new CubeColorSpace({
|
|
|
395
435
|
w: '#cdd6f4', // x+y+z
|
|
396
436
|
}).size(6);
|
|
397
437
|
|
|
398
|
-
|
|
438
|
+
r(4) // → strong red
|
|
399
439
|
tint({ r: 4, b: 2 }) // → red-blue blend
|
|
400
440
|
tint({ w: 3 }) // → mid-white (all axes at 3)
|
|
401
|
-
tint({ r: 5, w: 2 }) // → pastel red (white raises base)
|
|
402
|
-
tint.palette // → string[216] (6³)
|
|
403
441
|
```
|
|
404
442
|
|
|
405
443
|
#### Custom vocabulary
|
|
@@ -440,7 +478,7 @@ When you call `tint({ r: 4, b: 2 })`, each alias's mask is multiplied by its int
|
|
|
440
478
|
|
|
441
479
|
### Interpolation modes
|
|
442
480
|
|
|
443
|
-
|
|
481
|
+
`LinearColorSpace`, `PlaneColorSpace`, and `CubeColorSpace` all support configurable interpolation:
|
|
444
482
|
|
|
445
483
|
| Mode | Description |
|
|
446
484
|
|------|-------------|
|
|
@@ -453,24 +491,37 @@ Both `LinearColorSpace` and `CubeColorSpace` support configurable interpolation:
|
|
|
453
491
|
// LinearColorSpace
|
|
454
492
|
new LinearColorSpace('#ff0000', '#0000ff').interpolation('oklch').size(10)
|
|
455
493
|
new LinearColorSpace('#ff0000', '#0000ff').interpolation('lab').size(10)
|
|
456
|
-
new LinearColorSpace('#ff0000', '#0000ff').interpolation('rgb').size(10)
|
|
457
494
|
new LinearColorSpace('#f00', '#0f0', '#00f').interpolation(false).size(3)
|
|
458
495
|
|
|
496
|
+
// PlaneColorSpace
|
|
497
|
+
new PlaneColorSpace('#000', '#fff', '#f00').interpolation('oklch').size(6)
|
|
498
|
+
new PlaneColorSpace('#000', '#fff', '#f00').interpolation('lab').size(6)
|
|
499
|
+
|
|
459
500
|
// CubeColorSpace
|
|
460
|
-
new CubeColorSpace({ ... }
|
|
501
|
+
new CubeColorSpace({ ... }).interpolation('lab').size(6)
|
|
461
502
|
```
|
|
462
503
|
|
|
463
|
-
### Color
|
|
504
|
+
### Color accessor
|
|
505
|
+
|
|
506
|
+
All color space lookups return a `ColorAccessor` — a string that works directly in template literals and concatenation, with conversion methods:
|
|
507
|
+
|
|
508
|
+
```typescript
|
|
509
|
+
const c = red(3, 5);
|
|
510
|
+
`${c}` // → '#ab34cd' (string coercion)
|
|
511
|
+
'bg: ' + c // → 'bg: #ab34cd' (concatenation)
|
|
512
|
+
c.hex() // → '#ab34cd'
|
|
513
|
+
c.hsl() // → 'hsl(280, 60%, 50%)'
|
|
514
|
+
c.rgb() // → 'rgb(171, 52, 205)'
|
|
515
|
+
c.oklch() // → 'oklch(52.3% 0.198 310)'
|
|
516
|
+
c.luminance // → 0.52 (perceptual, 0–1)
|
|
517
|
+
```
|
|
464
518
|
|
|
465
|
-
|
|
519
|
+
Use `.format()` on the color space to change the default output format:
|
|
466
520
|
|
|
467
521
|
```typescript
|
|
468
|
-
const
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
color.format('rgb') // → 'rgb(171, 52, 205)'
|
|
472
|
-
color.format('oklch') // → 'oklch(52.3% 0.198 310)'
|
|
473
|
-
color.toString() // → '#ab34cd'
|
|
522
|
+
const rgbSpace = new PlaneColorSpace('#000', '#fff', '#f00').format('rgb').size(6);
|
|
523
|
+
`${rgbSpace(3, 5)}` // → 'rgb(255, 128, 128)'
|
|
524
|
+
rgbSpace(3, 5).hex() // → '#ff8080' (still available)
|
|
474
525
|
```
|
|
475
526
|
|
|
476
527
|
## Development
|
package/dist/index.d.ts
CHANGED
|
@@ -2,7 +2,8 @@ import { RampaBuilder } from './builder';
|
|
|
2
2
|
import { ReadOnlyBuilder } from './read-only';
|
|
3
3
|
import { LinearColorSpace } from './linear-color-space';
|
|
4
4
|
import { CubeColorSpace } from './cube-color-space';
|
|
5
|
-
import
|
|
5
|
+
import { PlaneColorSpace } from './plane-color-space';
|
|
6
|
+
import type { ColorFormat, ScaleType, BlendMode, HarmonyType, RampResult, RampaResult, ColorInfo, InterpolationMode, ColorResult, ColorAccessor, RgbComponents, LinearColorSpaceFn, CubeColorSpaceResult, PlaneColorSpaceResult, ColorSpaceOptions } from './types';
|
|
6
7
|
/**
|
|
7
8
|
* Create a new color ramp builder from a base color.
|
|
8
9
|
*
|
|
@@ -34,5 +35,5 @@ export declare namespace rampa {
|
|
|
34
35
|
* ```
|
|
35
36
|
*/
|
|
36
37
|
export declare function color(hex: string): ColorResult;
|
|
37
|
-
export { RampaBuilder, ReadOnlyBuilder, LinearColorSpace, CubeColorSpace };
|
|
38
|
-
export type { ColorFormat, ScaleType, BlendMode, HarmonyType, RampResult, RampaResult, ColorInfo, InterpolationMode, ColorResult, ColorAccessor, RgbComponents, LinearColorSpaceFn, CubeColorSpaceResult, ColorSpaceOptions, };
|
|
38
|
+
export { RampaBuilder, ReadOnlyBuilder, LinearColorSpace, CubeColorSpace, PlaneColorSpace };
|
|
39
|
+
export type { ColorFormat, ScaleType, BlendMode, HarmonyType, RampResult, RampaResult, ColorInfo, InterpolationMode, ColorResult, ColorAccessor, RgbComponents, LinearColorSpaceFn, CubeColorSpaceResult, PlaneColorSpaceResult, ColorSpaceOptions, };
|
package/dist/index.js
CHANGED
|
@@ -7939,6 +7939,21 @@ function generateCubeSpace(corners, stepsPerAxis, mode = "oklch") {
|
|
|
7939
7939
|
}
|
|
7940
7940
|
return colors;
|
|
7941
7941
|
}
|
|
7942
|
+
function generatePlaneSpace(dark, light, hue3, stepsPerAxis, mode = "oklch") {
|
|
7943
|
+
const mix = (a, b, t) => mixWithMode(a, b, t, mode);
|
|
7944
|
+
const max11 = stepsPerAxis - 1;
|
|
7945
|
+
const colors = [];
|
|
7946
|
+
for (let xi = 0;xi < stepsPerAxis; xi++) {
|
|
7947
|
+
const tx = max11 === 0 ? 0 : xi / max11;
|
|
7948
|
+
const bottom = dark;
|
|
7949
|
+
const top = mix(light, hue3, tx);
|
|
7950
|
+
for (let yi = 0;yi < stepsPerAxis; yi++) {
|
|
7951
|
+
const ty = max11 === 0 ? 0 : yi / max11;
|
|
7952
|
+
colors.push(mix(bottom, top, ty));
|
|
7953
|
+
}
|
|
7954
|
+
}
|
|
7955
|
+
return colors;
|
|
7956
|
+
}
|
|
7942
7957
|
|
|
7943
7958
|
// src/color-result.ts
|
|
7944
7959
|
function detectColorFormat(color) {
|
|
@@ -8147,6 +8162,46 @@ class CubeColorSpace {
|
|
|
8147
8162
|
}
|
|
8148
8163
|
}
|
|
8149
8164
|
|
|
8165
|
+
// src/plane-color-space.ts
|
|
8166
|
+
class PlaneColorSpace {
|
|
8167
|
+
_dark;
|
|
8168
|
+
_light;
|
|
8169
|
+
_hue;
|
|
8170
|
+
_interpolation;
|
|
8171
|
+
_format = "hex";
|
|
8172
|
+
constructor(dark, light, hue3) {
|
|
8173
|
+
validateSameFormat([dark, light, hue3]);
|
|
8174
|
+
this._dark = chroma_js_default(dark).hex();
|
|
8175
|
+
this._light = chroma_js_default(light).hex();
|
|
8176
|
+
this._hue = chroma_js_default(hue3).hex();
|
|
8177
|
+
this._interpolation = "oklch";
|
|
8178
|
+
}
|
|
8179
|
+
interpolation(mode) {
|
|
8180
|
+
this._interpolation = mode;
|
|
8181
|
+
return this;
|
|
8182
|
+
}
|
|
8183
|
+
format(fmt) {
|
|
8184
|
+
this._format = fmt;
|
|
8185
|
+
return this;
|
|
8186
|
+
}
|
|
8187
|
+
size(stepsPerAxis) {
|
|
8188
|
+
const palette = generatePlaneSpace(this._dark, this._light, this._hue, stepsPerAxis, this._interpolation);
|
|
8189
|
+
const fmt = this._format;
|
|
8190
|
+
const lookup = (saturation, lightness) => {
|
|
8191
|
+
const sx = Math.max(0, Math.min(stepsPerAxis - 1, saturation));
|
|
8192
|
+
const ly = Math.max(0, Math.min(stepsPerAxis - 1, lightness));
|
|
8193
|
+
const idx = sx * stepsPerAxis + ly;
|
|
8194
|
+
return createColorAccessor(palette[idx], fmt);
|
|
8195
|
+
};
|
|
8196
|
+
const result = lookup;
|
|
8197
|
+
Object.defineProperties(result, {
|
|
8198
|
+
palette: { value: palette, enumerable: true },
|
|
8199
|
+
size: { value: stepsPerAxis, enumerable: true }
|
|
8200
|
+
});
|
|
8201
|
+
return result;
|
|
8202
|
+
}
|
|
8203
|
+
}
|
|
8204
|
+
|
|
8150
8205
|
// ../src/usecases/MixColors.ts
|
|
8151
8206
|
function mixColors(color1, color2, t) {
|
|
8152
8207
|
const oklch1 = convertToOklch(color1);
|
|
@@ -8200,6 +8255,7 @@ export {
|
|
|
8200
8255
|
color,
|
|
8201
8256
|
ReadOnlyBuilder,
|
|
8202
8257
|
RampaBuilder,
|
|
8258
|
+
PlaneColorSpace,
|
|
8203
8259
|
LinearColorSpace,
|
|
8204
8260
|
CubeColorSpace
|
|
8205
8261
|
};
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import type { ColorFormat, InterpolationMode, PlaneColorSpaceResult } from './types';
|
|
2
|
+
/**
|
|
3
|
+
* Create a 2D color plane from dark, light, and hue anchors.
|
|
4
|
+
*
|
|
5
|
+
* The plane interpolates between 4 corners:
|
|
6
|
+
* (0,0) = dark — origin (bottom-left)
|
|
7
|
+
* (1,0) = dark — saturation has no effect at lightness=0
|
|
8
|
+
* (0,1) = light — achromatic light (top-left)
|
|
9
|
+
* (1,1) = hue — full chromatic color (top-right)
|
|
10
|
+
*
|
|
11
|
+
* Create one plane per hue, reusing the same dark/light anchors:
|
|
12
|
+
*
|
|
13
|
+
* @example
|
|
14
|
+
* ```ts
|
|
15
|
+
* const red = new PlaneColorSpace('#1e1e2e', '#cdd6f4', '#f38ba8').size(6);
|
|
16
|
+
* const blue = new PlaneColorSpace('#1e1e2e', '#cdd6f4', '#89b4fa').size(6);
|
|
17
|
+
*
|
|
18
|
+
* red(3, 5) // → ColorAccessor (saturation=3, lightness=5)
|
|
19
|
+
* red(0, 3) // → achromatic at lightness 3
|
|
20
|
+
* red.palette // → string[36] (6²)
|
|
21
|
+
*
|
|
22
|
+
* // With different interpolation or output format:
|
|
23
|
+
* new PlaneColorSpace(dark, light, hue).interpolation('lab').format('rgb').size(8);
|
|
24
|
+
* ```
|
|
25
|
+
*/
|
|
26
|
+
export declare class PlaneColorSpace {
|
|
27
|
+
private _dark;
|
|
28
|
+
private _light;
|
|
29
|
+
private _hue;
|
|
30
|
+
private _interpolation;
|
|
31
|
+
private _format;
|
|
32
|
+
constructor(dark: string, light: string, hue: string);
|
|
33
|
+
interpolation(mode: InterpolationMode): this;
|
|
34
|
+
format(fmt: ColorFormat): this;
|
|
35
|
+
size(stepsPerAxis: number): PlaneColorSpaceResult;
|
|
36
|
+
}
|
package/dist/types.d.ts
CHANGED
|
@@ -105,3 +105,15 @@ export interface CubeColorSpaceResult {
|
|
|
105
105
|
/** Per-corner shortcut functions, keyed by constructor key names */
|
|
106
106
|
[key: string]: ((index: number) => ColorAccessor) | string[] | number | ((query: Record<string, number>) => ColorAccessor) | ((x: number, y: number, z: number) => ColorAccessor);
|
|
107
107
|
}
|
|
108
|
+
/**
|
|
109
|
+
* The result returned by PlaneColorSpace.size().
|
|
110
|
+
* Callable with (saturation, lightness) to look up colors on the 2D plane.
|
|
111
|
+
*/
|
|
112
|
+
export interface PlaneColorSpaceResult {
|
|
113
|
+
/** Look up a color by 2D coordinates (both 0-based, clamped to size-1) */
|
|
114
|
+
(saturation: number, lightness: number): ColorAccessor;
|
|
115
|
+
/** Full palette array (length = size²) */
|
|
116
|
+
palette: string[];
|
|
117
|
+
/** Steps per axis */
|
|
118
|
+
size: number;
|
|
119
|
+
}
|