@ansh-ui/core 0.2.0
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/LICENSE +21 -0
- package/dist/behaviours.cjs +64 -0
- package/dist/behaviours.cjs.map +1 -0
- package/dist/behaviours.d.cts +3 -0
- package/dist/behaviours.d.ts +3 -0
- package/dist/behaviours.js +7 -0
- package/dist/behaviours.js.map +1 -0
- package/dist/chunk-23GSSIMK.cjs +439 -0
- package/dist/chunk-23GSSIMK.cjs.map +1 -0
- package/dist/chunk-56NNBIAO.js +2446 -0
- package/dist/chunk-56NNBIAO.js.map +1 -0
- package/dist/chunk-6PFYGJWD.cjs +136 -0
- package/dist/chunk-6PFYGJWD.cjs.map +1 -0
- package/dist/chunk-7MEIXWPH.js +313 -0
- package/dist/chunk-7MEIXWPH.js.map +1 -0
- package/dist/chunk-7MYTSAPR.js +83 -0
- package/dist/chunk-7MYTSAPR.js.map +1 -0
- package/dist/chunk-BOQQHICI.js +1036 -0
- package/dist/chunk-BOQQHICI.js.map +1 -0
- package/dist/chunk-C6XPQO2O.js +1170 -0
- package/dist/chunk-C6XPQO2O.js.map +1 -0
- package/dist/chunk-DXJ63QAR.cjs +723 -0
- package/dist/chunk-DXJ63QAR.cjs.map +1 -0
- package/dist/chunk-FAVIEION.js +705 -0
- package/dist/chunk-FAVIEION.js.map +1 -0
- package/dist/chunk-FNR35HTL.cjs +107 -0
- package/dist/chunk-FNR35HTL.cjs.map +1 -0
- package/dist/chunk-GHBRGMSO.cjs +91 -0
- package/dist/chunk-GHBRGMSO.cjs.map +1 -0
- package/dist/chunk-GJRIHN76.cjs +359 -0
- package/dist/chunk-GJRIHN76.cjs.map +1 -0
- package/dist/chunk-ILKUL7GD.cjs +115 -0
- package/dist/chunk-ILKUL7GD.cjs.map +1 -0
- package/dist/chunk-KTUBCQC3.js +409 -0
- package/dist/chunk-KTUBCQC3.js.map +1 -0
- package/dist/chunk-KU2C6GEA.js +90 -0
- package/dist/chunk-KU2C6GEA.js.map +1 -0
- package/dist/chunk-LGA3N3YJ.cjs +413 -0
- package/dist/chunk-LGA3N3YJ.cjs.map +1 -0
- package/dist/chunk-MMO7KO53.cjs +1060 -0
- package/dist/chunk-MMO7KO53.cjs.map +1 -0
- package/dist/chunk-NSXKCJJ7.js +109 -0
- package/dist/chunk-NSXKCJJ7.js.map +1 -0
- package/dist/chunk-QALZKHWH.js +387 -0
- package/dist/chunk-QALZKHWH.js.map +1 -0
- package/dist/chunk-R7UJ7MWP.cjs +2479 -0
- package/dist/chunk-R7UJ7MWP.cjs.map +1 -0
- package/dist/chunk-UJBXY6QC.cjs +1186 -0
- package/dist/chunk-UJBXY6QC.cjs.map +1 -0
- package/dist/chunk-YFQXRC5R.js +99 -0
- package/dist/chunk-YFQXRC5R.js.map +1 -0
- package/dist/color.cjs +257 -0
- package/dist/color.cjs.map +1 -0
- package/dist/color.d.cts +303 -0
- package/dist/color.d.ts +303 -0
- package/dist/color.js +8 -0
- package/dist/color.js.map +1 -0
- package/dist/easing.cjs +189 -0
- package/dist/easing.cjs.map +1 -0
- package/dist/easing.d.cts +134 -0
- package/dist/easing.d.ts +134 -0
- package/dist/easing.js +4 -0
- package/dist/easing.js.map +1 -0
- package/dist/effects.cjs +99 -0
- package/dist/effects.cjs.map +1 -0
- package/dist/effects.d.cts +5 -0
- package/dist/effects.d.ts +5 -0
- package/dist/effects.js +10 -0
- package/dist/effects.js.map +1 -0
- package/dist/index-CCdpefMp.d.ts +967 -0
- package/dist/index-CQEEPu-D.d.ts +435 -0
- package/dist/index-DHOfsEIn.d.cts +967 -0
- package/dist/index-Dl8GCsya.d.cts +435 -0
- package/dist/index.cjs +2206 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +1122 -0
- package/dist/index.d.ts +1122 -0
- package/dist/index.js +1182 -0
- package/dist/index.js.map +1 -0
- package/dist/math.cjs +238 -0
- package/dist/math.cjs.map +1 -0
- package/dist/math.d.cts +120 -0
- package/dist/math.d.ts +120 -0
- package/dist/math.js +5 -0
- package/dist/math.js.map +1 -0
- package/dist/noise.cjs +78 -0
- package/dist/noise.cjs.map +1 -0
- package/dist/noise.d.cts +190 -0
- package/dist/noise.d.ts +190 -0
- package/dist/noise.js +5 -0
- package/dist/noise.js.map +1 -0
- package/dist/palette-6HkVltYU.d.cts +219 -0
- package/dist/palette-6HkVltYU.d.ts +219 -0
- package/dist/random--4mSc5Lp.d.cts +75 -0
- package/dist/random--4mSc5Lp.d.ts +75 -0
- package/dist/reduced-motion-D0LUgZle.d.cts +120 -0
- package/dist/reduced-motion-D0LUgZle.d.ts +120 -0
- package/dist/types-B1FLLf3-.d.cts +21 -0
- package/dist/types-B1FLLf3-.d.ts +21 -0
- package/package.json +78 -0
package/dist/noise.d.ts
ADDED
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Fractal composition of a base noise function.
|
|
3
|
+
*
|
|
4
|
+
* A single octave of simplex noise is smooth and featureless. Real natural texture comes from
|
|
5
|
+
* summing octaves at increasing frequency and decreasing amplitude — fractional Brownian
|
|
6
|
+
* motion. This module provides the standard family of summations, all parameterised so that
|
|
7
|
+
* no frequency, amplitude, or octave count is hardcoded inside an effect.
|
|
8
|
+
*/
|
|
9
|
+
type Noise2DFn = (x: number, y: number) => number;
|
|
10
|
+
type Noise3DFn = (x: number, y: number, z: number) => number;
|
|
11
|
+
interface FractalOptions {
|
|
12
|
+
/**
|
|
13
|
+
* Number of summed layers. Each octave roughly doubles the cost, and beyond ~6 the added
|
|
14
|
+
* detail is below a pixel for typical scales. Default `4`.
|
|
15
|
+
*/
|
|
16
|
+
octaves?: number;
|
|
17
|
+
/** Frequency multiplier per octave. `2` is the classic choice. Default `2`. */
|
|
18
|
+
lacunarity?: number;
|
|
19
|
+
/**
|
|
20
|
+
* Amplitude multiplier per octave. Also called persistence. `0.5` gives the pink-noise
|
|
21
|
+
* falloff that reads as natural. Default `0.5`.
|
|
22
|
+
*/
|
|
23
|
+
gain?: number;
|
|
24
|
+
/** Frequency of the first octave. Default `1`. */
|
|
25
|
+
frequency?: number;
|
|
26
|
+
/** Amplitude of the first octave. Default `1`. */
|
|
27
|
+
amplitude?: number;
|
|
28
|
+
/**
|
|
29
|
+
* Normalise the result back into `[-1, 1]` by dividing by the total amplitude.
|
|
30
|
+
* Without this, more octaves means a quieter signal. Default `true`.
|
|
31
|
+
*/
|
|
32
|
+
normalize?: boolean;
|
|
33
|
+
}
|
|
34
|
+
declare const FRACTAL_DEFAULTS: {
|
|
35
|
+
readonly octaves: 4;
|
|
36
|
+
readonly lacunarity: 2;
|
|
37
|
+
readonly gain: 0.5;
|
|
38
|
+
readonly frequency: 1;
|
|
39
|
+
readonly amplitude: 1;
|
|
40
|
+
readonly normalize: true;
|
|
41
|
+
};
|
|
42
|
+
/** Standard fBm over a 2D noise source. Output in `[-1, 1]` when normalised. */
|
|
43
|
+
declare function fbm2D(noise: Noise2DFn, options?: FractalOptions): Noise2DFn;
|
|
44
|
+
/** Standard fBm over a 3D noise source — use the third axis as time for animated fields. */
|
|
45
|
+
declare function fbm3D(noise: Noise3DFn, options?: FractalOptions): Noise3DFn;
|
|
46
|
+
/**
|
|
47
|
+
* Ridged multifractal. Inverts and sharpens each octave (`1 - |n|`, squared), producing crisp
|
|
48
|
+
* ridge lines instead of rolling hills. This is what makes convincing mountain silhouettes,
|
|
49
|
+
* lightning, and the filament structure in aurora curtains.
|
|
50
|
+
*
|
|
51
|
+
* Output is in `[0, 1]`.
|
|
52
|
+
*/
|
|
53
|
+
declare function ridged2D(noise: Noise2DFn, options?: FractalOptions): Noise2DFn;
|
|
54
|
+
/**
|
|
55
|
+
* Turbulence: fBm over the absolute value of each octave. Produces the billowing,
|
|
56
|
+
* smoke-like structure used for clouds and flame.
|
|
57
|
+
*
|
|
58
|
+
* Output is in `[0, 1]`.
|
|
59
|
+
*/
|
|
60
|
+
declare function turbulence2D(noise: Noise2DFn, options?: FractalOptions): Noise2DFn;
|
|
61
|
+
/**
|
|
62
|
+
* Domain warping — feed noise through itself.
|
|
63
|
+
*
|
|
64
|
+
* `warp(p) = noise(p + strength * noise(p))`. This single trick is responsible for most of
|
|
65
|
+
* the "organic liquid" look in modern generative backgrounds: it turns the isotropic blobs of
|
|
66
|
+
* plain fBm into flowing, marbled filaments.
|
|
67
|
+
*
|
|
68
|
+
* @param strength How far the domain is displaced, in noise-space units. `0.5`–`2` is useful.
|
|
69
|
+
*/
|
|
70
|
+
declare function warp2D(noise: Noise2DFn, strength?: number, offset?: number): Noise2DFn;
|
|
71
|
+
interface CurlResult {
|
|
72
|
+
x: number;
|
|
73
|
+
y: number;
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Curl (divergence-free) noise for 2D flow fields.
|
|
77
|
+
*
|
|
78
|
+
* A particle advected by raw noise will pool in sinks and thin out in sources, because the
|
|
79
|
+
* field has non-zero divergence. Taking the perpendicular gradient of a scalar potential —
|
|
80
|
+
* `(∂N/∂y, −∂N/∂x)` — yields a field with zero divergence, so particle density is preserved
|
|
81
|
+
* and the motion looks like real fluid.
|
|
82
|
+
*
|
|
83
|
+
* The derivative is a central difference; `epsilon` trades accuracy against smoothness.
|
|
84
|
+
*/
|
|
85
|
+
declare function curl2D(noise: Noise2DFn, epsilon?: number): (x: number, y: number) => CurlResult;
|
|
86
|
+
/** The 3D-source variant of {@link curl2D}, letting you animate the field over time. */
|
|
87
|
+
declare function curl2DAnimated(noise: Noise3DFn, epsilon?: number): (x: number, y: number, t: number) => CurlResult;
|
|
88
|
+
/**
|
|
89
|
+
* Make a 2D noise field seamlessly tileable over `[0, width) × [0, height)`.
|
|
90
|
+
*
|
|
91
|
+
* Works by sampling 4D noise on the surface of a torus: each axis becomes a circle, so the
|
|
92
|
+
* field wraps exactly with no seam. This is the correct way to do it — blending mirrored
|
|
93
|
+
* copies leaves visible symmetry artefacts.
|
|
94
|
+
*/
|
|
95
|
+
declare function tileable2D(noise4D: (x: number, y: number, z: number, w: number) => number, width: number, height: number): Noise2DFn;
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Gradient tables and permutation setup shared by every noise variant.
|
|
99
|
+
*
|
|
100
|
+
* The permutation table is a shuffled `0..255` sequence duplicated to 512 entries. Doubling
|
|
101
|
+
* it lets the noise functions index `perm[i + perm[j]]` without a modulo on every lookup,
|
|
102
|
+
* which matters when these run millions of times per second.
|
|
103
|
+
*
|
|
104
|
+
* The table is derived from the effect's seed, so noise fields are reproducible — the same
|
|
105
|
+
* seed always produces the same landscape.
|
|
106
|
+
*/
|
|
107
|
+
/** 12 edge-midpoint gradients of a cube. Used by 2D and 3D noise. */
|
|
108
|
+
declare const GRAD3: Float32Array<ArrayBuffer>;
|
|
109
|
+
/** 32 gradients for 4D noise — the edge midpoints of a hypercube. */
|
|
110
|
+
declare const GRAD4: Float32Array<ArrayBuffer>;
|
|
111
|
+
interface NoiseTables {
|
|
112
|
+
/** 512-entry doubled permutation table. */
|
|
113
|
+
readonly perm: Uint8Array;
|
|
114
|
+
/** `perm[i] % 12`, precomputed — saves a modulo in the inner loop of 2D/3D noise. */
|
|
115
|
+
readonly permMod12: Uint8Array;
|
|
116
|
+
/** `perm[i] % 32`, precomputed for 4D noise. */
|
|
117
|
+
readonly permMod32: Uint8Array;
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* Build (or reuse) permutation tables for a seed.
|
|
121
|
+
*
|
|
122
|
+
* Tables are 1.5 KB each and construction costs a shuffle, so we memoise them. The cache is
|
|
123
|
+
* bounded because a page that animates its seed would otherwise grow it without limit; we
|
|
124
|
+
* evict oldest-first, which suits the access pattern (a handful of stable seeds per page).
|
|
125
|
+
*/
|
|
126
|
+
declare function createNoiseTables(seed?: number): NoiseTables;
|
|
127
|
+
/** Clear the memoised permutation tables. Exposed for tests and long-lived workers. */
|
|
128
|
+
declare function clearNoiseTableCache(): void;
|
|
129
|
+
|
|
130
|
+
interface SimplexNoise {
|
|
131
|
+
noise2D(x: number, y: number): number;
|
|
132
|
+
noise3D(x: number, y: number, z: number): number;
|
|
133
|
+
noise4D(x: number, y: number, z: number, w: number): number;
|
|
134
|
+
}
|
|
135
|
+
declare function createSimplexNoise(seed?: number): SimplexNoise;
|
|
136
|
+
|
|
137
|
+
interface PerlinNoise {
|
|
138
|
+
noise2D(x: number, y: number): number;
|
|
139
|
+
noise3D(x: number, y: number, z: number): number;
|
|
140
|
+
}
|
|
141
|
+
declare function createPerlinNoise(seed?: number): PerlinNoise;
|
|
142
|
+
/**
|
|
143
|
+
* Value noise: interpolates hashed *values* at lattice points rather than gradients.
|
|
144
|
+
*
|
|
145
|
+
* Cheaper than gradient noise and blockier in character. Good for film grain, dithering and
|
|
146
|
+
* any place you want visible cell structure rather than smooth flow.
|
|
147
|
+
*/
|
|
148
|
+
declare function createValueNoise(seed?: number): {
|
|
149
|
+
noise2D(x: number, y: number): number;
|
|
150
|
+
};
|
|
151
|
+
|
|
152
|
+
/**
|
|
153
|
+
* The one-stop noise factory.
|
|
154
|
+
*
|
|
155
|
+
* Effects generally want several related fields from a single seed — a base simplex, an fBm
|
|
156
|
+
* for the large structure, and a curl field for advection. Creating them individually would
|
|
157
|
+
* rebuild the permutation table each time (it is cached, but the wiring is still repetitive),
|
|
158
|
+
* so `createNoise(seed)` hands back a coherent bundle.
|
|
159
|
+
*
|
|
160
|
+
* ```ts
|
|
161
|
+
* const noise = createNoise('hero')
|
|
162
|
+
* const height = noise.fbm2D({ octaves: 5, gain: 0.55 })
|
|
163
|
+
* const flow = noise.curl({ octaves: 2 })
|
|
164
|
+
* ```
|
|
165
|
+
*/
|
|
166
|
+
declare function createNoise(seed?: number | string): {
|
|
167
|
+
seed: number;
|
|
168
|
+
/** Raw single-octave sources. */
|
|
169
|
+
simplex2D: (x: number, y: number) => number;
|
|
170
|
+
simplex3D: (x: number, y: number, z: number) => number;
|
|
171
|
+
simplex4D: (x: number, y: number, z: number, w: number) => number;
|
|
172
|
+
perlin2D: (x: number, y: number) => number;
|
|
173
|
+
perlin3D: (x: number, y: number, z: number) => number;
|
|
174
|
+
value2D: (x: number, y: number) => number;
|
|
175
|
+
/** Fractal compositions over simplex. */
|
|
176
|
+
fbm2D: (options?: FractalOptions) => Noise2DFn;
|
|
177
|
+
fbm3D: (options?: FractalOptions) => Noise3DFn;
|
|
178
|
+
ridged2D: (options?: FractalOptions) => Noise2DFn;
|
|
179
|
+
turbulence2D: (options?: FractalOptions) => Noise2DFn;
|
|
180
|
+
/** Domain-warped fBm — the organic, marbled look. */
|
|
181
|
+
warped2D: (strength?: number, options?: FractalOptions) => Noise2DFn;
|
|
182
|
+
/** Divergence-free flow field for particle advection. */
|
|
183
|
+
curl: (options?: FractalOptions) => (x: number, y: number) => CurlResult;
|
|
184
|
+
curlAnimated: (options?: FractalOptions) => (x: number, y: number, t: number) => CurlResult;
|
|
185
|
+
/** Seamlessly tiling field over the given extent. */
|
|
186
|
+
tileable: (width: number, height: number) => Noise2DFn;
|
|
187
|
+
};
|
|
188
|
+
type Noise = ReturnType<typeof createNoise>;
|
|
189
|
+
|
|
190
|
+
export { type CurlResult, FRACTAL_DEFAULTS, type FractalOptions, GRAD3, GRAD4, type Noise, type Noise2DFn, type Noise3DFn, type NoiseTables, type PerlinNoise, type SimplexNoise, clearNoiseTableCache, createNoise, createNoiseTables, createPerlinNoise, createSimplexNoise, createValueNoise, curl2D, curl2DAnimated, fbm2D, fbm3D, ridged2D, tileable2D, turbulence2D, warp2D };
|
package/dist/noise.js
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export { FRACTAL_DEFAULTS, GRAD3, GRAD4, clearNoiseTableCache, createNoise, createNoiseTables, createPerlinNoise, createSimplexNoise, createValueNoise, curl2D, curl2DAnimated, fbm2D, fbm3D, ridged2D, tileable2D, turbulence2D, warp2D } from './chunk-FAVIEION.js';
|
|
2
|
+
import './chunk-YFQXRC5R.js';
|
|
3
|
+
import './chunk-KU2C6GEA.js';
|
|
4
|
+
//# sourceMappingURL=noise.js.map
|
|
5
|
+
//# sourceMappingURL=noise.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"names":[],"mappings":"","file":"noise.js"}
|
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Colour model types.
|
|
3
|
+
*
|
|
4
|
+
* The engine's canonical internal representation is {@link Rgb}: sRGB components and alpha,
|
|
5
|
+
* all normalised to `[0, 1]`. Everything parses *into* it and formats *out of* it. Working in
|
|
6
|
+
* `0..1` rather than `0..255` avoids repeated division in the interpolation hot path and
|
|
7
|
+
* matches how every other colour space here is expressed.
|
|
8
|
+
*/
|
|
9
|
+
/** sRGB with alpha, components in `[0, 1]`. The canonical form. */
|
|
10
|
+
interface Rgb {
|
|
11
|
+
r: number;
|
|
12
|
+
g: number;
|
|
13
|
+
b: number;
|
|
14
|
+
a: number;
|
|
15
|
+
}
|
|
16
|
+
/** Linear-light RGB (gamma removed), components in `[0, 1]`. */
|
|
17
|
+
interface LinearRgb {
|
|
18
|
+
r: number;
|
|
19
|
+
g: number;
|
|
20
|
+
b: number;
|
|
21
|
+
a: number;
|
|
22
|
+
}
|
|
23
|
+
/** Hue in degrees `[0, 360)`, saturation and lightness in `[0, 1]`. */
|
|
24
|
+
interface Hsl {
|
|
25
|
+
h: number;
|
|
26
|
+
s: number;
|
|
27
|
+
l: number;
|
|
28
|
+
a: number;
|
|
29
|
+
}
|
|
30
|
+
/** Hue in degrees `[0, 360)`, saturation and value in `[0, 1]`. */
|
|
31
|
+
interface Hsv {
|
|
32
|
+
h: number;
|
|
33
|
+
s: number;
|
|
34
|
+
v: number;
|
|
35
|
+
a: number;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* OKLab — a perceptually uniform opponent-colour space.
|
|
39
|
+
*
|
|
40
|
+
* `l` is perceived lightness in `[0, 1]`; `a` (green↔red) and `b` (blue↔yellow) are roughly
|
|
41
|
+
* in `[-0.4, 0.4]`. Equal numeric steps here correspond to equal perceived steps, which is
|
|
42
|
+
* exactly what you want when interpolating or generating scales.
|
|
43
|
+
*/
|
|
44
|
+
interface Oklab {
|
|
45
|
+
l: number;
|
|
46
|
+
a: number;
|
|
47
|
+
b: number;
|
|
48
|
+
alpha: number;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* OKLCH — the cylindrical form of OKLab.
|
|
52
|
+
*
|
|
53
|
+
* `l` lightness `[0, 1]`, `c` chroma (`0` grey, ~`0.37` maximum for sRGB primaries),
|
|
54
|
+
* `h` hue in degrees `[0, 360)`. This is the space to reason about when building palettes:
|
|
55
|
+
* hold `l` and `c` fixed, rotate `h`, and every result has matching perceived weight.
|
|
56
|
+
*/
|
|
57
|
+
interface Oklch {
|
|
58
|
+
l: number;
|
|
59
|
+
c: number;
|
|
60
|
+
h: number;
|
|
61
|
+
alpha: number;
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Interpolation spaces, in rough order of how good they look.
|
|
65
|
+
*
|
|
66
|
+
* - `oklab` — the default. Perceptually uniform, no dead grey midpoints, no hue drift.
|
|
67
|
+
* - `oklch` — like `oklab` but travels around the hue circle, keeping chroma high through
|
|
68
|
+
* the transition. Best for vivid gradients between distant hues.
|
|
69
|
+
* - `lrgb` — linear RGB. Physically correct light mixing; what a real spotlight does.
|
|
70
|
+
* - `srgb` — naive component blending. Fast, and what CSS gradients historically did, so
|
|
71
|
+
* pick it when you must match an existing design exactly.
|
|
72
|
+
* - `hsl` — legacy; included for parity with older tooling.
|
|
73
|
+
*/
|
|
74
|
+
type ColorSpace = 'oklab' | 'oklch' | 'lrgb' | 'srgb' | 'hsl';
|
|
75
|
+
/** Direction to travel around the hue circle when interpolating in a cylindrical space. */
|
|
76
|
+
type HueDirection = 'shorter' | 'longer' | 'increasing' | 'decreasing';
|
|
77
|
+
/**
|
|
78
|
+
* Anything the engine accepts where a colour is expected.
|
|
79
|
+
*
|
|
80
|
+
* Strings cover every CSS syntax (`#0275f4`, `rgb()`, `hsl()`, `oklch()`, named colours,
|
|
81
|
+
* and `var(--token)` which resolves against the document at mount time).
|
|
82
|
+
*/
|
|
83
|
+
type ColorInput = string | Rgb | Oklch | Oklab | Hsl;
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Palette generation in OKLCH.
|
|
87
|
+
*
|
|
88
|
+
* Generating a scale by scaling HSL lightness produces the familiar problem where the
|
|
89
|
+
* "same" adjustment makes yellow wash out and blue go muddy — because HSL lightness is not
|
|
90
|
+
* perceptual. Doing it in OKLCH means step 500 of a blue scale and step 500 of a yellow scale
|
|
91
|
+
* have genuinely matching visual weight, which is what makes a generated theme usable.
|
|
92
|
+
*/
|
|
93
|
+
type HarmonyKind = 'analogous' | 'complementary' | 'splitComplementary' | 'triadic' | 'tetradic' | 'square' | 'monochromatic';
|
|
94
|
+
/**
|
|
95
|
+
* Derive a set of harmonious colours from a base.
|
|
96
|
+
*
|
|
97
|
+
* Chroma and lightness are preserved from the base and each result is gamut-mapped, so a
|
|
98
|
+
* harmony built from a displayable colour is always itself displayable.
|
|
99
|
+
*/
|
|
100
|
+
declare function harmony(base: ColorInput, kind?: HarmonyKind): Rgb[];
|
|
101
|
+
interface ScaleOptions {
|
|
102
|
+
/**
|
|
103
|
+
* Number of steps. `11` matches the Tailwind convention (50–950) and is the default,
|
|
104
|
+
* because that is the shape most consumers will slot this into.
|
|
105
|
+
*/
|
|
106
|
+
steps?: number;
|
|
107
|
+
/** Lightness of the lightest step, in OKLCH `[0, 1]`. Default `0.97`. */
|
|
108
|
+
lightest?: number;
|
|
109
|
+
/** Lightness of the darkest step. Default `0.18`. */
|
|
110
|
+
darkest?: number;
|
|
111
|
+
/**
|
|
112
|
+
* How much chroma falls off at the extremes, in `[0, 1]`.
|
|
113
|
+
*
|
|
114
|
+
* Real pigments lose saturation as they approach white or black, and scales that hold
|
|
115
|
+
* chroma constant look artificial at the ends. `0.35` is a natural-looking default.
|
|
116
|
+
*/
|
|
117
|
+
chromaFalloff?: number;
|
|
118
|
+
/**
|
|
119
|
+
* Hue drift across the scale, in degrees.
|
|
120
|
+
*
|
|
121
|
+
* Slightly warming the light end and cooling the dark end (or vice versa) is what makes
|
|
122
|
+
* hand-tuned scales feel considered. Default `0` — opt in deliberately.
|
|
123
|
+
*/
|
|
124
|
+
hueShift?: number;
|
|
125
|
+
}
|
|
126
|
+
interface ColorScale {
|
|
127
|
+
/** The generated colours, lightest first. */
|
|
128
|
+
colors: Rgb[];
|
|
129
|
+
/** Hex strings, lightest first. Convenient for theme output. */
|
|
130
|
+
hex: string[];
|
|
131
|
+
/** Tailwind-style numeric keys when `steps` is 11, otherwise `0..steps-1`. */
|
|
132
|
+
byKey: Record<string, string>;
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* Build a lightness scale from a single seed colour.
|
|
136
|
+
*
|
|
137
|
+
* The seed's own hue and chroma anchor the scale; its lightness is *not* preserved, since the
|
|
138
|
+
* point of a scale is to span the range. Use `scale.colors[5]` (or key `500`) as the closest
|
|
139
|
+
* equivalent of the input.
|
|
140
|
+
*/
|
|
141
|
+
declare function createScale(base: ColorInput, options?: ScaleOptions): ColorScale;
|
|
142
|
+
interface PaletteOptions {
|
|
143
|
+
/** Number of colours to generate. Default `5`. */
|
|
144
|
+
count?: number;
|
|
145
|
+
/** Seed for the stochastic variation. Same seed ⇒ same palette. Default `1`. */
|
|
146
|
+
seed?: number | string;
|
|
147
|
+
/**
|
|
148
|
+
* Overall lightness of the palette in `[0, 1]`. `0.75` reads as pastel, `0.5` as vivid,
|
|
149
|
+
* `0.3` as moody. Default `0.65`.
|
|
150
|
+
*/
|
|
151
|
+
lightness?: number;
|
|
152
|
+
/** Chroma as a fraction of the maximum available at each hue, in `[0, 1]`. Default `0.85`. */
|
|
153
|
+
saturation?: number;
|
|
154
|
+
/** Total hue span in degrees the palette covers. Default `120`. */
|
|
155
|
+
spread?: number;
|
|
156
|
+
/** Starting hue in degrees. Random (but seeded) when omitted. */
|
|
157
|
+
baseHue?: number;
|
|
158
|
+
/** Random variation applied to lightness and chroma, in `[0, 1]`. Default `0.12`. */
|
|
159
|
+
variance?: number;
|
|
160
|
+
}
|
|
161
|
+
/**
|
|
162
|
+
* Generate a coherent palette from scratch.
|
|
163
|
+
*
|
|
164
|
+
* Hues are distributed with a golden-ratio walk rather than evenly, because even spacing
|
|
165
|
+
* produces the flat, obviously-computed look of an auto-generated chart palette. The walk
|
|
166
|
+
* gives spacing that reads as deliberate.
|
|
167
|
+
*/
|
|
168
|
+
declare function generatePalette(options?: PaletteOptions): Rgb[];
|
|
169
|
+
/**
|
|
170
|
+
* Extend a short palette to `count` colours by interpolating between the ones given.
|
|
171
|
+
*
|
|
172
|
+
* Effects that need N colours (a mesh gradient with 6 control points, say) shouldn't force
|
|
173
|
+
* the author to supply exactly N. This fills the gap perceptually, so the extras look like
|
|
174
|
+
* they belong to the same palette rather than like interpolation artefacts.
|
|
175
|
+
*/
|
|
176
|
+
declare function expandPalette(colors: readonly ColorInput[], count: number): Rgb[];
|
|
177
|
+
/**
|
|
178
|
+
* Sort a palette by perceived lightness. Ascending puts the darkest first.
|
|
179
|
+
* Layered effects use this so that lighter colours land on top by default.
|
|
180
|
+
*/
|
|
181
|
+
declare function sortByLightness(colors: readonly ColorInput[], ascending?: boolean): Rgb[];
|
|
182
|
+
/**
|
|
183
|
+
* Derive a palette suited to a dark surface from one designed for light (or vice versa).
|
|
184
|
+
*
|
|
185
|
+
* Not a lightness inversion — that ruins hue relationships. Instead lightness is reflected
|
|
186
|
+
* about the midpoint while chroma is *raised*, compensating for the fact that saturated
|
|
187
|
+
* colours read as less vivid against dark backgrounds (the Helmholtz–Kohlrausch effect).
|
|
188
|
+
*/
|
|
189
|
+
declare function invertForSurface(colors: readonly ColorInput[], chromaBoost?: number): Rgb[];
|
|
190
|
+
/**
|
|
191
|
+
* The Ansh signature palettes.
|
|
192
|
+
*
|
|
193
|
+
* These are the defaults every effect falls back to when no colours are supplied. They are
|
|
194
|
+
* chosen so that a developer who writes `<AuroraBackground />` with no props gets something
|
|
195
|
+
* that looks like a considered design decision rather than a debug view.
|
|
196
|
+
*/
|
|
197
|
+
declare const palettes: {
|
|
198
|
+
/** Deep blue → violet → magenta. The house palette. */
|
|
199
|
+
readonly ansh: readonly ["#0275f4", "#5b3df5", "#9f0550"];
|
|
200
|
+
/** Cool northern lights: teal, green, indigo. */
|
|
201
|
+
readonly aurora: readonly ["#00d4ff", "#22e39a", "#4f46e5"];
|
|
202
|
+
/** Warm dusk: amber through rose. */
|
|
203
|
+
readonly ember: readonly ["#ff9d00", "#ff4d6d", "#c026d3"];
|
|
204
|
+
/** Oceanic blues and cyans. */
|
|
205
|
+
readonly abyss: readonly ["#012a4a", "#0275f4", "#00d4ff"];
|
|
206
|
+
/** Monochrome with a cool cast — for restrained, editorial designs. */
|
|
207
|
+
readonly graphite: readonly ["#f8fafc", "#94a3b8", "#0f172a"];
|
|
208
|
+
/** High-energy neon for AI and developer-tool aesthetics. */
|
|
209
|
+
readonly neon: readonly ["#00d4ff", "#8a2be2", "#ff0066"];
|
|
210
|
+
/** Soft pastel wash for marketing and onboarding. */
|
|
211
|
+
readonly bloom: readonly ["#fbcfe8", "#c7d2fe", "#a7f3d0"];
|
|
212
|
+
/** Gold and bronze — luxury, premium tiers, testimonials. */
|
|
213
|
+
readonly gilded: readonly ["#fde68a", "#d97706", "#78350f"];
|
|
214
|
+
};
|
|
215
|
+
type PaletteName = keyof typeof palettes;
|
|
216
|
+
/** Resolve a palette name, an explicit colour list, or `undefined` (→ the house palette). */
|
|
217
|
+
declare function resolvePalette(input: PaletteName | readonly ColorInput[] | undefined, fallback?: PaletteName): Rgb[];
|
|
218
|
+
|
|
219
|
+
export { type ColorSpace as C, type HarmonyKind as H, type LinearRgb as L, type Oklab as O, type PaletteName as P, type Rgb as R, type ScaleOptions as S, type ColorInput as a, type ColorScale as b, type Hsl as c, type Hsv as d, type HueDirection as e, type Oklch as f, type PaletteOptions as g, createScale as h, expandPalette as i, generatePalette as j, harmony as k, invertForSurface as l, palettes as p, resolvePalette as r, sortByLightness as s };
|
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Colour model types.
|
|
3
|
+
*
|
|
4
|
+
* The engine's canonical internal representation is {@link Rgb}: sRGB components and alpha,
|
|
5
|
+
* all normalised to `[0, 1]`. Everything parses *into* it and formats *out of* it. Working in
|
|
6
|
+
* `0..1` rather than `0..255` avoids repeated division in the interpolation hot path and
|
|
7
|
+
* matches how every other colour space here is expressed.
|
|
8
|
+
*/
|
|
9
|
+
/** sRGB with alpha, components in `[0, 1]`. The canonical form. */
|
|
10
|
+
interface Rgb {
|
|
11
|
+
r: number;
|
|
12
|
+
g: number;
|
|
13
|
+
b: number;
|
|
14
|
+
a: number;
|
|
15
|
+
}
|
|
16
|
+
/** Linear-light RGB (gamma removed), components in `[0, 1]`. */
|
|
17
|
+
interface LinearRgb {
|
|
18
|
+
r: number;
|
|
19
|
+
g: number;
|
|
20
|
+
b: number;
|
|
21
|
+
a: number;
|
|
22
|
+
}
|
|
23
|
+
/** Hue in degrees `[0, 360)`, saturation and lightness in `[0, 1]`. */
|
|
24
|
+
interface Hsl {
|
|
25
|
+
h: number;
|
|
26
|
+
s: number;
|
|
27
|
+
l: number;
|
|
28
|
+
a: number;
|
|
29
|
+
}
|
|
30
|
+
/** Hue in degrees `[0, 360)`, saturation and value in `[0, 1]`. */
|
|
31
|
+
interface Hsv {
|
|
32
|
+
h: number;
|
|
33
|
+
s: number;
|
|
34
|
+
v: number;
|
|
35
|
+
a: number;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* OKLab — a perceptually uniform opponent-colour space.
|
|
39
|
+
*
|
|
40
|
+
* `l` is perceived lightness in `[0, 1]`; `a` (green↔red) and `b` (blue↔yellow) are roughly
|
|
41
|
+
* in `[-0.4, 0.4]`. Equal numeric steps here correspond to equal perceived steps, which is
|
|
42
|
+
* exactly what you want when interpolating or generating scales.
|
|
43
|
+
*/
|
|
44
|
+
interface Oklab {
|
|
45
|
+
l: number;
|
|
46
|
+
a: number;
|
|
47
|
+
b: number;
|
|
48
|
+
alpha: number;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* OKLCH — the cylindrical form of OKLab.
|
|
52
|
+
*
|
|
53
|
+
* `l` lightness `[0, 1]`, `c` chroma (`0` grey, ~`0.37` maximum for sRGB primaries),
|
|
54
|
+
* `h` hue in degrees `[0, 360)`. This is the space to reason about when building palettes:
|
|
55
|
+
* hold `l` and `c` fixed, rotate `h`, and every result has matching perceived weight.
|
|
56
|
+
*/
|
|
57
|
+
interface Oklch {
|
|
58
|
+
l: number;
|
|
59
|
+
c: number;
|
|
60
|
+
h: number;
|
|
61
|
+
alpha: number;
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Interpolation spaces, in rough order of how good they look.
|
|
65
|
+
*
|
|
66
|
+
* - `oklab` — the default. Perceptually uniform, no dead grey midpoints, no hue drift.
|
|
67
|
+
* - `oklch` — like `oklab` but travels around the hue circle, keeping chroma high through
|
|
68
|
+
* the transition. Best for vivid gradients between distant hues.
|
|
69
|
+
* - `lrgb` — linear RGB. Physically correct light mixing; what a real spotlight does.
|
|
70
|
+
* - `srgb` — naive component blending. Fast, and what CSS gradients historically did, so
|
|
71
|
+
* pick it when you must match an existing design exactly.
|
|
72
|
+
* - `hsl` — legacy; included for parity with older tooling.
|
|
73
|
+
*/
|
|
74
|
+
type ColorSpace = 'oklab' | 'oklch' | 'lrgb' | 'srgb' | 'hsl';
|
|
75
|
+
/** Direction to travel around the hue circle when interpolating in a cylindrical space. */
|
|
76
|
+
type HueDirection = 'shorter' | 'longer' | 'increasing' | 'decreasing';
|
|
77
|
+
/**
|
|
78
|
+
* Anything the engine accepts where a colour is expected.
|
|
79
|
+
*
|
|
80
|
+
* Strings cover every CSS syntax (`#0275f4`, `rgb()`, `hsl()`, `oklch()`, named colours,
|
|
81
|
+
* and `var(--token)` which resolves against the document at mount time).
|
|
82
|
+
*/
|
|
83
|
+
type ColorInput = string | Rgb | Oklch | Oklab | Hsl;
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Palette generation in OKLCH.
|
|
87
|
+
*
|
|
88
|
+
* Generating a scale by scaling HSL lightness produces the familiar problem where the
|
|
89
|
+
* "same" adjustment makes yellow wash out and blue go muddy — because HSL lightness is not
|
|
90
|
+
* perceptual. Doing it in OKLCH means step 500 of a blue scale and step 500 of a yellow scale
|
|
91
|
+
* have genuinely matching visual weight, which is what makes a generated theme usable.
|
|
92
|
+
*/
|
|
93
|
+
type HarmonyKind = 'analogous' | 'complementary' | 'splitComplementary' | 'triadic' | 'tetradic' | 'square' | 'monochromatic';
|
|
94
|
+
/**
|
|
95
|
+
* Derive a set of harmonious colours from a base.
|
|
96
|
+
*
|
|
97
|
+
* Chroma and lightness are preserved from the base and each result is gamut-mapped, so a
|
|
98
|
+
* harmony built from a displayable colour is always itself displayable.
|
|
99
|
+
*/
|
|
100
|
+
declare function harmony(base: ColorInput, kind?: HarmonyKind): Rgb[];
|
|
101
|
+
interface ScaleOptions {
|
|
102
|
+
/**
|
|
103
|
+
* Number of steps. `11` matches the Tailwind convention (50–950) and is the default,
|
|
104
|
+
* because that is the shape most consumers will slot this into.
|
|
105
|
+
*/
|
|
106
|
+
steps?: number;
|
|
107
|
+
/** Lightness of the lightest step, in OKLCH `[0, 1]`. Default `0.97`. */
|
|
108
|
+
lightest?: number;
|
|
109
|
+
/** Lightness of the darkest step. Default `0.18`. */
|
|
110
|
+
darkest?: number;
|
|
111
|
+
/**
|
|
112
|
+
* How much chroma falls off at the extremes, in `[0, 1]`.
|
|
113
|
+
*
|
|
114
|
+
* Real pigments lose saturation as they approach white or black, and scales that hold
|
|
115
|
+
* chroma constant look artificial at the ends. `0.35` is a natural-looking default.
|
|
116
|
+
*/
|
|
117
|
+
chromaFalloff?: number;
|
|
118
|
+
/**
|
|
119
|
+
* Hue drift across the scale, in degrees.
|
|
120
|
+
*
|
|
121
|
+
* Slightly warming the light end and cooling the dark end (or vice versa) is what makes
|
|
122
|
+
* hand-tuned scales feel considered. Default `0` — opt in deliberately.
|
|
123
|
+
*/
|
|
124
|
+
hueShift?: number;
|
|
125
|
+
}
|
|
126
|
+
interface ColorScale {
|
|
127
|
+
/** The generated colours, lightest first. */
|
|
128
|
+
colors: Rgb[];
|
|
129
|
+
/** Hex strings, lightest first. Convenient for theme output. */
|
|
130
|
+
hex: string[];
|
|
131
|
+
/** Tailwind-style numeric keys when `steps` is 11, otherwise `0..steps-1`. */
|
|
132
|
+
byKey: Record<string, string>;
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* Build a lightness scale from a single seed colour.
|
|
136
|
+
*
|
|
137
|
+
* The seed's own hue and chroma anchor the scale; its lightness is *not* preserved, since the
|
|
138
|
+
* point of a scale is to span the range. Use `scale.colors[5]` (or key `500`) as the closest
|
|
139
|
+
* equivalent of the input.
|
|
140
|
+
*/
|
|
141
|
+
declare function createScale(base: ColorInput, options?: ScaleOptions): ColorScale;
|
|
142
|
+
interface PaletteOptions {
|
|
143
|
+
/** Number of colours to generate. Default `5`. */
|
|
144
|
+
count?: number;
|
|
145
|
+
/** Seed for the stochastic variation. Same seed ⇒ same palette. Default `1`. */
|
|
146
|
+
seed?: number | string;
|
|
147
|
+
/**
|
|
148
|
+
* Overall lightness of the palette in `[0, 1]`. `0.75` reads as pastel, `0.5` as vivid,
|
|
149
|
+
* `0.3` as moody. Default `0.65`.
|
|
150
|
+
*/
|
|
151
|
+
lightness?: number;
|
|
152
|
+
/** Chroma as a fraction of the maximum available at each hue, in `[0, 1]`. Default `0.85`. */
|
|
153
|
+
saturation?: number;
|
|
154
|
+
/** Total hue span in degrees the palette covers. Default `120`. */
|
|
155
|
+
spread?: number;
|
|
156
|
+
/** Starting hue in degrees. Random (but seeded) when omitted. */
|
|
157
|
+
baseHue?: number;
|
|
158
|
+
/** Random variation applied to lightness and chroma, in `[0, 1]`. Default `0.12`. */
|
|
159
|
+
variance?: number;
|
|
160
|
+
}
|
|
161
|
+
/**
|
|
162
|
+
* Generate a coherent palette from scratch.
|
|
163
|
+
*
|
|
164
|
+
* Hues are distributed with a golden-ratio walk rather than evenly, because even spacing
|
|
165
|
+
* produces the flat, obviously-computed look of an auto-generated chart palette. The walk
|
|
166
|
+
* gives spacing that reads as deliberate.
|
|
167
|
+
*/
|
|
168
|
+
declare function generatePalette(options?: PaletteOptions): Rgb[];
|
|
169
|
+
/**
|
|
170
|
+
* Extend a short palette to `count` colours by interpolating between the ones given.
|
|
171
|
+
*
|
|
172
|
+
* Effects that need N colours (a mesh gradient with 6 control points, say) shouldn't force
|
|
173
|
+
* the author to supply exactly N. This fills the gap perceptually, so the extras look like
|
|
174
|
+
* they belong to the same palette rather than like interpolation artefacts.
|
|
175
|
+
*/
|
|
176
|
+
declare function expandPalette(colors: readonly ColorInput[], count: number): Rgb[];
|
|
177
|
+
/**
|
|
178
|
+
* Sort a palette by perceived lightness. Ascending puts the darkest first.
|
|
179
|
+
* Layered effects use this so that lighter colours land on top by default.
|
|
180
|
+
*/
|
|
181
|
+
declare function sortByLightness(colors: readonly ColorInput[], ascending?: boolean): Rgb[];
|
|
182
|
+
/**
|
|
183
|
+
* Derive a palette suited to a dark surface from one designed for light (or vice versa).
|
|
184
|
+
*
|
|
185
|
+
* Not a lightness inversion — that ruins hue relationships. Instead lightness is reflected
|
|
186
|
+
* about the midpoint while chroma is *raised*, compensating for the fact that saturated
|
|
187
|
+
* colours read as less vivid against dark backgrounds (the Helmholtz–Kohlrausch effect).
|
|
188
|
+
*/
|
|
189
|
+
declare function invertForSurface(colors: readonly ColorInput[], chromaBoost?: number): Rgb[];
|
|
190
|
+
/**
|
|
191
|
+
* The Ansh signature palettes.
|
|
192
|
+
*
|
|
193
|
+
* These are the defaults every effect falls back to when no colours are supplied. They are
|
|
194
|
+
* chosen so that a developer who writes `<AuroraBackground />` with no props gets something
|
|
195
|
+
* that looks like a considered design decision rather than a debug view.
|
|
196
|
+
*/
|
|
197
|
+
declare const palettes: {
|
|
198
|
+
/** Deep blue → violet → magenta. The house palette. */
|
|
199
|
+
readonly ansh: readonly ["#0275f4", "#5b3df5", "#9f0550"];
|
|
200
|
+
/** Cool northern lights: teal, green, indigo. */
|
|
201
|
+
readonly aurora: readonly ["#00d4ff", "#22e39a", "#4f46e5"];
|
|
202
|
+
/** Warm dusk: amber through rose. */
|
|
203
|
+
readonly ember: readonly ["#ff9d00", "#ff4d6d", "#c026d3"];
|
|
204
|
+
/** Oceanic blues and cyans. */
|
|
205
|
+
readonly abyss: readonly ["#012a4a", "#0275f4", "#00d4ff"];
|
|
206
|
+
/** Monochrome with a cool cast — for restrained, editorial designs. */
|
|
207
|
+
readonly graphite: readonly ["#f8fafc", "#94a3b8", "#0f172a"];
|
|
208
|
+
/** High-energy neon for AI and developer-tool aesthetics. */
|
|
209
|
+
readonly neon: readonly ["#00d4ff", "#8a2be2", "#ff0066"];
|
|
210
|
+
/** Soft pastel wash for marketing and onboarding. */
|
|
211
|
+
readonly bloom: readonly ["#fbcfe8", "#c7d2fe", "#a7f3d0"];
|
|
212
|
+
/** Gold and bronze — luxury, premium tiers, testimonials. */
|
|
213
|
+
readonly gilded: readonly ["#fde68a", "#d97706", "#78350f"];
|
|
214
|
+
};
|
|
215
|
+
type PaletteName = keyof typeof palettes;
|
|
216
|
+
/** Resolve a palette name, an explicit colour list, or `undefined` (→ the house palette). */
|
|
217
|
+
declare function resolvePalette(input: PaletteName | readonly ColorInput[] | undefined, fallback?: PaletteName): Rgb[];
|
|
218
|
+
|
|
219
|
+
export { type ColorSpace as C, type HarmonyKind as H, type LinearRgb as L, type Oklab as O, type PaletteName as P, type Rgb as R, type ScaleOptions as S, type ColorInput as a, type ColorScale as b, type Hsl as c, type Hsv as d, type HueDirection as e, type Oklch as f, type PaletteOptions as g, createScale as h, expandPalette as i, generatePalette as j, harmony as k, invertForSurface as l, palettes as p, resolvePalette as r, sortByLightness as s };
|