@roobscoob/vibes 0.0.0-stage → 0.1.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.
Files changed (59) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +254 -2
  3. package/dist/arclamp.d.ts +34 -0
  4. package/dist/arclamp.d.ts.map +1 -0
  5. package/dist/arclamp.js +5 -0
  6. package/dist/color.d.ts +199 -0
  7. package/dist/color.d.ts.map +1 -0
  8. package/dist/color.js +491 -0
  9. package/dist/field.d.ts +94 -0
  10. package/dist/field.d.ts.map +1 -0
  11. package/dist/field.js +232 -0
  12. package/dist/gamut.d.ts +5 -0
  13. package/dist/gamut.d.ts.map +1 -0
  14. package/dist/gamut.js +29 -0
  15. package/dist/gamut.table.d.ts +5 -0
  16. package/dist/gamut.table.d.ts.map +1 -0
  17. package/dist/gamut.table.js +153 -0
  18. package/dist/here.d.ts +103 -0
  19. package/dist/here.d.ts.map +1 -0
  20. package/dist/here.js +217 -0
  21. package/dist/index.d.ts +8 -0
  22. package/dist/index.d.ts.map +1 -0
  23. package/dist/index.js +8 -0
  24. package/dist/lemtone.d.ts +37 -0
  25. package/dist/lemtone.d.ts.map +1 -0
  26. package/dist/lemtone.js +158 -0
  27. package/dist/names.d.ts +5 -0
  28. package/dist/names.d.ts.map +1 -0
  29. package/dist/names.js +46 -0
  30. package/dist/parse.d.ts +43 -0
  31. package/dist/parse.d.ts.map +1 -0
  32. package/dist/parse.js +208 -0
  33. package/dist/shape.d.ts +44 -0
  34. package/dist/shape.d.ts.map +1 -0
  35. package/dist/shape.js +89 -0
  36. package/dist/signal.d.ts +26 -0
  37. package/dist/signal.d.ts.map +1 -0
  38. package/dist/signal.js +44 -0
  39. package/dist/sketch.d.ts +21 -0
  40. package/dist/sketch.d.ts.map +1 -0
  41. package/dist/sketch.js +89 -0
  42. package/dist/spaces.d.ts +24 -0
  43. package/dist/spaces.d.ts.map +1 -0
  44. package/dist/spaces.js +91 -0
  45. package/package.json +24 -4
  46. package/src/arclamp.ts +36 -0
  47. package/src/color.ts +586 -0
  48. package/src/field.ts +321 -0
  49. package/src/gamut.table.ts +156 -0
  50. package/src/gamut.ts +32 -0
  51. package/src/here.ts +270 -0
  52. package/src/index.ts +52 -0
  53. package/src/lemtone.ts +180 -0
  54. package/src/names.ts +50 -0
  55. package/src/parse.ts +205 -0
  56. package/src/shape.ts +109 -0
  57. package/src/signal.ts +65 -0
  58. package/src/sketch.ts +116 -0
  59. package/src/spaces.ts +102 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Rose Kodsi-Hall
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,3 +1,255 @@
1
- # Temporary Holding Version
1
+ # @roobscoob/vibes
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ Color, light and time for sketches on the lights at the
4
+ [Recurse Center](https://www.recurse.com): the room's color bulbs, 4×1
5
+ panels and old on/off bulbs, run by arclamp and made in vibes.
6
+
7
+ ```sh
8
+ npm install @roobscoob/vibes
9
+ ```
10
+
11
+ ```ts
12
+ import { sketch, white, wave } from "@roobscoob/vibes";
13
+
14
+ // A slow warm wave rolls across the room.
15
+ export const update = sketch(({ x, t }) => white(2700, 30 + 400 * wave(t / 8 - x / 12)));
16
+ ```
17
+
18
+ ## One light, now
19
+
20
+ A sketch says what each light should make, a hundred times a second.
21
+ `sketch()` asks your function once per light per tick, and gives it `here`:
22
+
23
+ | | |
24
+ |---|---|
25
+ | `x`, `y` | where the light is, in meters from the building's top-left corner |
26
+ | `u`, `v` | the same, 0 to 1 across the room the lights fill (left to right, top to bottom) |
27
+ | `t` | seconds since the sketch started |
28
+ | `dt` | seconds since the last tick (about 0.01 in the room, 0.03 in the preview) |
29
+ | `now` | the clock, in ms since 1970 |
30
+ | `light` | the light itself: `id`, `kind` (`"color"` or `"switch"`), `tags`, `has(tag)`, `rail`, `random`, `below`, `state` |
31
+ | `room` | every light: `lights`, `rails`, `rail(id)`, `tagged(tag)`, `width`, `depth`, `center` |
32
+ | `at({ x, y, t })` | the same light, looking from somewhere else or at another time |
33
+
34
+ Return a color (anything that says one: see below), or `null` to leave the
35
+ light as the layers below have it. `sketch("#f80")` makes every light one
36
+ color; `sketch(palettes.dusk)` lays a palette across the room.
37
+
38
+ - `light.rail` is `{ id, along, t, index, count }`: how far along its rail
39
+ (meters, and 0 to 1), its place on it, and how many share it.
40
+ - `light.random` is a number from 0 to 1 of its own, the same every time.
41
+ - `light.below` is what the layers below this sketch make it, as a color.
42
+ - `light.state` is the light's own memory, kept from tick to tick.
43
+
44
+ Old bulbs only switch: `sketch()` turns them on at 100 lm or more and off
45
+ below 70 (`sketch(fn, { switchOn, switchOff })` to change that). Something
46
+ that isn't a color leaves its light as it is, with a warning in the console,
47
+ so one slip doesn't stop the sketch.
48
+
49
+ ## Colors
50
+
51
+ A color is light: a hue and chroma (OKLab's a and b at full lightness), and
52
+ an amount of light in **lumens**. Lumens are absolute, the same on every
53
+ light: 800 lm is a bright bulb, 20 lm a glow, whichever bulb it lands on.
54
+
55
+ Colors never change. Read them with properties, and change them with
56
+ methods, each giving a new color:
57
+
58
+ ```ts
59
+ const warm = white(2700).at(400);
60
+ warm.mix("#ff8800", 0.3).fade(0.5);
61
+ light.below.shiftHue(20).dim(0.8); // a filter over what's below
62
+ ```
63
+
64
+ ### Making them
65
+
66
+ ```ts
67
+ white(2700, 400) // a white by color temperature, 400 lm
68
+ lemtone(265, 0.3, 40) // the lights' own: hue, chroma at full lightness, lumens
69
+ oklch(0.7, 0.2, 265) // CSS's oklch()
70
+ hsl(240, 1, 0.5) // the familiar wheel: 0 red, 120 green, 240 blue
71
+ rgb(1, 0.5, 0) // 0–1, or 0–255
72
+ hex("#ff8800")
73
+ xy(0.3127, 0.329, 500) // CIE 1931 chromaticity, lumens
74
+ color(anything) // anything below
75
+ off
76
+ ```
77
+
78
+ Screens' spaces (RGB, hex, HSL, OKLCh, …) count a screen's white as a fixed
79
+ 1000 lm: `#ffffff` is 1000 lm, `#0000ff` about 72, `oklch(0.5 0 0)` 125, as
80
+ dim next to white as on a screen. `white()` and `lemtone()` take lumens
81
+ straight (1000 if not given), and `.at(lm)` sets them on any color.
82
+
83
+ Hues in the lights' own terms (`lemtone`, `c.hue`) are OKLab's: about 30°
84
+ red, 110° yellow, 145° green, 195° cyan, 265° blue, 330° magenta. They're
85
+ not HSL's, which is why `hsl()` is its own maker. Chroma: 0 is white, 0.1
86
+ pale, 0.3 strong.
87
+
88
+ ### Anything that says a color
89
+
90
+ Wherever a color goes (`color()`, `.mix()`, `.add()`, palettes, fields,
91
+ what your look returns, `sketch()` itself), anything that says one will do:
92
+
93
+ | | |
94
+ |---|---|
95
+ | text | any CSS color: `"#f80"`, `"ff8800cc"`, `"orange"`, `"rgb(255 136 0 / 50%)"`, `"hsl(30deg, 100%, 50%)"`, `"hwb(…)"`, `"oklch(70% 0.2 265)"`, `"oklab(…)"`, `"lab(…)"`, `"lch(…)"`, `"color(display-p3 1 0 0)"` |
96
+ | | color temperatures: `"2700K"`, `"2700 kelvin"`, `"candlelight"`, `"incandescent"`, `"halogen"`, `"daylight"` |
97
+ | | the lights' own: `"lemtone(265 0.3 40)"`, and `"265° C0.300 · 40 lm"` (as a color prints itself) |
98
+ | | with lumens or fidelity alongside: `"#f80 · 120 lm"`, `"2700K @ 400lm"`, `"orange 50 lumens"`, `"… · F0.5"` |
99
+ | a number | a color temperature in kelvin: `2700` |
100
+ | a list | `[r, g, b]` or `[r, g, b, alpha]`, 0–1 or 0–255 |
101
+ | an object | `{ a, b, lm }`, arclamp's channels `{ a, b, brightness, fidelity }`, `{ r, g, b }`, `{ h, s, l }`, `{ l, c, h }`, `{ hue, chroma, lm }`, `{ kelvin, lm }`, `{ x, y }`, an old bulb's `{ on }`, with `lm`, `lumens`, `brightness` or `fidelity` on any |
102
+ | nothing | `null` or `undefined` is `off` |
103
+
104
+ Alpha is less light: `#ff880080` is half the lumens of `#ff8800`.
105
+ Something it can't read throws, saying what it would take.
106
+
107
+ ### Reading them
108
+
109
+ | | |
110
+ |---|---|
111
+ | `c.lm`, `c.brightness` | lumens; arclamp's units (1.0 is 1000 lm) |
112
+ | `c.hue`, `c.chroma` | in the lights' own terms |
113
+ | `c.kelvin`, `c.nearestKelvin` | its color temperature if it's a white (else null); the nearest white's |
114
+ | `c.looks` | how bright it looks, 0–1 (1000 lm and up is 1) |
115
+ | `c.hex`, `c.rgb`, `c.hsl`, `c.oklch`, `c.oklab`, `c.xy`, `c.xyz` | in other spaces, on the same 1000 lm scale (`rgb` goes past 1 when brighter) |
116
+ | `c.channels` | arclamp's channels |
117
+ | `` `${c}` `` | `"2700 K · 400 lm"`, which `color()` reads back |
118
+
119
+ ### Changing them
120
+
121
+ | | |
122
+ |---|---|
123
+ | `.at(lm)` | the same color at `lm` lumens |
124
+ | `.dim(k)`, `.fade(k)` | k times the lumens; looks k times as bright |
125
+ | `.mix(other, t)` | toward another color by t (0.5 if not given), evenly as it looks; to or from dark, only brightness changes |
126
+ | `.add(...others)` | lights shining together, added up as light |
127
+ | `.shiftHue(deg)`, `.saturate(k)` | |
128
+ | `.with({ … })` | any of `a`, `b`, `hue`, `chroma`, `kelvin`, `lm`, `brightness`, `fidelity` changed |
129
+ | `.vivid()` | dimmed to what a color bulb makes of it, so it isn't paled |
130
+
131
+ ### Palettes
132
+
133
+ `palette(a, b, c)` is colors from 0 to 1: `palette(a, b, c)(0.5)` is `b`.
134
+ Stops can be anything that says a color, in a list, or placed:
135
+ `palette([0, "black"], [0.2, "#f80"], [1, 6500])`. Outside 0–1 it holds the
136
+ ends. `palettes.dusk`, `.sea`, `.ember` and `.aurora` start you off, each
137
+ dark to bright, within what the bulbs make.
138
+
139
+ ### What bulbs make
140
+
141
+ **Saturated colors are dim.** A color bulb's strongest blue tops out near
142
+ 30 lm; asked for more, a bulb keeps the lumens and pales the color toward
143
+ white. `c.vivid()` dims it instead, so it stays the color you asked for, and
144
+ `br30.maxLm(c)` says how bright a color can be on a color bulb (`br30` is
145
+ arclamp's name for them). Whites go brightest around 4000 K (about 950 lm),
146
+ and 2700 K reaches about 500; the bulbs go no warmer than about 1800 K, and
147
+ only dimly there. 4×1 panels have no model yet.
148
+
149
+ ## Fields
150
+
151
+ A field is a pattern over the room and time: a function of `here`, with
152
+ methods to chain. Sources make numbers from 0 to 1, a palette makes them
153
+ colors, and `sketch()` takes the result.
154
+
155
+ ```ts
156
+ import { sketch, osc, noise, palettes } from "@roobscoob/vibes";
157
+
158
+ export const update = sketch(
159
+ osc(3, 0.05) // 3 bands across the room, each light going round 0.05 times a second
160
+ .rotate(({ t }) => t * 6) // any number can be a function of here: 6° a second
161
+ .kaleid(5)
162
+ .warp(noise(2, 0.1), 1.5) // pushed up to 1.5 m by slow noise
163
+ .color(palettes.dusk),
164
+ );
165
+ ```
166
+
167
+ Sources count across the room's width, from its center.
168
+
169
+ | Sources | |
170
+ |---|---|
171
+ | `osc(n, speed, phase)` | smooth bands, n across the room |
172
+ | `noise(n, speed)` | smooth noise, blobs about n across |
173
+ | `rings(n, speed)` | rings out from the center |
174
+ | `gradient(degrees)` | 0 to 1 across the room: 0° left to right, 90° top to bottom |
175
+ | `voronoi(n, speed)` | drifting cells, 0 at their centers |
176
+ | `solid(value)` | the same everywhere, a number or a color |
177
+ | `field(fn)` | your own function of here, to chain onto |
178
+
179
+ `speed` is how many times a second each light goes round.
180
+
181
+ | Methods | |
182
+ |---|---|
183
+ | `.rotate(deg)`, `.scale(k)`, `.move(dx, dy)`, `.kaleid(n)`, `.warp(field, meters)` | where it looks |
184
+ | `.delay(seconds)`, `.speed(k)` | when it looks: `.delay(({ u }) => 2 * u)` runs later across the room |
185
+ | `.pow(k)`, `.steps(n)`, `.thresh(level)`, `.invert()`, `.mul(k)`, `.add(x)`, `.mix(x, t)` | numbers |
186
+ | `.color(palette)` | numbers to colors: a palette, a list of stops (`["black", "#f80", "white"]`), one color (dark to it), or your own function |
187
+ | `.at(lm)`, `.dim(k)`, `.fade(k)`, `.boost(by, amount)`, `.shiftHue(deg)`, `.saturate(k)`, `.vivid()`, `.add(color)`, `.mix(color, t)` | colors |
188
+ | `.map(fn)` | your own change: `.map((v, here) => ...)` |
189
+ | `.only(test)` | just some lights: `.only((light) => light.rail)` |
190
+
191
+ Transforms move where and when a field looks, never which light it is.
192
+
193
+ ## Both at once
194
+
195
+ A field is a function of `here`, so your function can read one, and
196
+ `field()` makes your function chainable:
197
+
198
+ ```ts
199
+ const petals = osc(3, 0.05).rotate(({ t }) => t * 6).kaleid(5);
200
+
201
+ export const update = sketch((here) => {
202
+ const { light, t } = here;
203
+ if (light.rail) return palettes.sea(petals(here)).vivid(); // bulbs on rails show the petals
204
+ return white(2200, 200 * wave(t / 4 + light.random)); // panels breathe, each on its own beat
205
+ });
206
+ ```
207
+
208
+ Nothing needs a chain: every transform is also a plain function on `here`
209
+ (`rotate(here, 30)`, `kaleid(here, 5)`, `delay(here, 1)`, …).
210
+
211
+ ## Time
212
+
213
+ Waves count in cycles and run 0 to 1: `wave(t / 8)` goes round every 8 s.
214
+
215
+ | | |
216
+ |---|---|
217
+ | `wave`, `saw`, `tri`, `square(x, duty)` | smooth, rising, up and down, on and off |
218
+ | `ease.in`, `ease.out`, `ease.inOut`, `smoothstep`, `lerp`, `remap`, `clamp`, `fract` | |
219
+ | `noiseAt(x, y, z)` | smooth noise from any numbers |
220
+ | `hash(...ns)` | a number from 0 to 1 that's the same for the same inputs |
221
+ | `decay(dt, halfLife)` | `v *= decay(dt, 2)` halves v every 2 s |
222
+ | `chance(perSecond, dt)` | true as often as something happening that many times a second |
223
+
224
+ The room ticks about three times as often as the preview, so anything done
225
+ each tick should use `dt`: `decay` and `chance` do.
226
+
227
+ A clock counts beats, for wiring into any number a field takes:
228
+
229
+ ```ts
230
+ const beat = clock(96);
231
+ const hit = beat.every(1).env({ attack: 0.02, release: 0.45 }); // 0 → 1 → 0 on every beat
232
+ const turn = beat.every(4).seq([0, 45, 90, 135]); // a hard step each bar
233
+ const look = beat.every(16).seq([palettes.dusk, palettes.sea]);
234
+
235
+ export const update = sketch(osc(4, 0.1).rotate(turn).kaleid(6).color(look).boost(hit, 0.8));
236
+ ```
237
+
238
+ `every(n)` also gives `count`, `ramp` (0 to 1 between marks) and `since`.
239
+
240
+ ## Without sketch()
241
+
242
+ `sketch()` makes arclamp's `update(prev, nowMs, initialMs)`, which you can
243
+ write yourself: it gets every light (`id`, `channels`, `tags`, `coords`,
244
+ `rail`) and returns `{ lights: [{ id, channels }] }`. Color lights' channels
245
+ are `a`, `b`, `brightness` (1.0 = 1000 lm) and `fidelity`; old bulbs' is `on`.
246
+ `color(light.channels)` reads a light's channels, and `c.channels` writes
247
+ them. The types are `Prev`, `Out` and `Update`.
248
+
249
+ ## Working on this library
250
+
251
+ It lives in vibes (`packages/vibes`). `node packages/vibes/scripts/gamut.ts`
252
+ remakes the color bulbs' table from vibes' model of them; `npm run build` in
253
+ this folder makes `dist/`.
254
+
255
+ MIT licensed.
@@ -0,0 +1,34 @@
1
+ /** Where a light is: millimeters on its floor's plan, from the building's top-left wall corner. */
2
+ export interface Coords {
3
+ mm_x: number;
4
+ mm_y: number;
5
+ floor: number;
6
+ }
7
+ /** A light as update() is given it. */
8
+ export interface PrevLight {
9
+ id: number;
10
+ /** A color bulb's or panel's a, b, brightness (1.0 = 1000 lm) and fidelity, or an old bulb's on. */
11
+ channels: Record<string, number>;
12
+ tags?: string[] | null;
13
+ /** Null until the light has been placed. */
14
+ coords?: Coords | null;
15
+ /** The rail it hangs on, and how far along it from the rail's start. */
16
+ rail?: {
17
+ id: string;
18
+ mm_along: number;
19
+ } | null;
20
+ }
21
+ export interface Prev {
22
+ initial_time: number;
23
+ lights: PrevLight[];
24
+ }
25
+ /** The lights to change, and their channels; anything left out keeps its value from below. */
26
+ export interface Out {
27
+ lights: {
28
+ id: number;
29
+ channels: Record<string, number>;
30
+ }[];
31
+ }
32
+ /** arclamp's shader entry point. */
33
+ export type Update = (prev: Prev, nowMs: number, initialMs: number) => Out;
34
+ //# sourceMappingURL=arclamp.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"arclamp.d.ts","sourceRoot":"","sources":["../src/arclamp.ts"],"names":[],"mappings":"AAKA,mGAAmG;AACnG,MAAM,WAAW,MAAM;IACrB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;CACf;AAED,uCAAuC;AACvC,MAAM,WAAW,SAAS;IACxB,EAAE,EAAE,MAAM,CAAC;IACX,oGAAoG;IACpG,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjC,IAAI,CAAC,EAAE,MAAM,EAAE,GAAG,IAAI,CAAC;IACvB,4CAA4C;IAC5C,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,wEAAwE;IACxE,IAAI,CAAC,EAAE;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC;CAChD;AAED,MAAM,WAAW,IAAI;IACnB,YAAY,EAAE,MAAM,CAAC;IACrB,MAAM,EAAE,SAAS,EAAE,CAAC;CACrB;AAED,8FAA8F;AAC9F,MAAM,WAAW,GAAG;IAClB,MAAM,EAAE;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;KAAE,EAAE,CAAC;CAC5D;AAED,oCAAoC;AACpC,MAAM,MAAM,MAAM,GAAG,CAAC,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,KAAK,GAAG,CAAC"}
@@ -0,0 +1,5 @@
1
+ // What update() is given, and gives back: arclamp's shader contract
2
+ // (rclamp backend/internal/state ToJSObject). update(prev, nowMs, initialMs)
3
+ // runs about a hundred times a second, with every light as the layers below
4
+ // left it, and says what each should be making now.
5
+ export {};
@@ -0,0 +1,199 @@
1
+ import { type Vec3 } from "./lemtone.ts";
2
+ /** Anything that says a color: see the top of color.ts. */
3
+ export type ColorInput = Color | string | number | readonly number[] | {
4
+ readonly [key: string]: unknown;
5
+ };
6
+ /** A color, given anywhere but as a number (which in a field is a number, not a color temperature). */
7
+ export type ColorLike = Exclude<ColorInput, number>;
8
+ /** What Color.with() changes: any of these, the rest kept. */
9
+ export interface ColorChanges {
10
+ a?: number;
11
+ b?: number;
12
+ hue?: number;
13
+ chroma?: number;
14
+ kelvin?: number;
15
+ lm?: number;
16
+ lumens?: number;
17
+ /** In arclamp's units: 1.0 is 1000 lm. */
18
+ brightness?: number;
19
+ fidelity?: number;
20
+ }
21
+ export declare class Color {
22
+ /** OKLab's a at full lightness: green (−) to red (+). */
23
+ readonly a: number;
24
+ /** OKLab's b at full lightness: blue (−) to yellow (+). */
25
+ readonly b: number;
26
+ /** How much light, in lumens. */
27
+ readonly lm: number;
28
+ /** 0 builds pale colors and whites from the RGB LEDs, 1 from the white ones. */
29
+ readonly fidelity: number;
30
+ constructor(a: number, b: number, lm: number, fidelity?: number);
31
+ /** Reads anything that says a color, as color() does. */
32
+ static from(input: ColorInput, lm?: number): Color;
33
+ /** Its hue in degrees, 0–360 (OKLab's: about 30 red, 110 yellow, 145 green, 265 blue, 330 magenta). */
34
+ get hue(): number;
35
+ /** How saturated: 0 is white, 0.1 pale, 0.3 strong. */
36
+ get chroma(): number;
37
+ /** Its color temperature, if it's a white; null if it isn't. */
38
+ get kelvin(): number | null;
39
+ /** The color temperature of the white nearest it, white or not. */
40
+ get nearestKelvin(): number;
41
+ /** How bright it looks, 0–1 (the cube root of its light; 1000 lm and up is 1). */
42
+ get looks(): number;
43
+ /** Its brightness in arclamp's units: 1.0 is 1000 lm. */
44
+ get brightness(): number;
45
+ /** As arclamp's channels for a color light. */
46
+ get channels(): {
47
+ a: number;
48
+ b: number;
49
+ brightness: number;
50
+ fidelity: number;
51
+ };
52
+ /** As CIE XYZ (D65), with Y = 1 for 1000 lm. */
53
+ get xyz(): Vec3;
54
+ /** Its CIE 1931 chromaticity. */
55
+ get xy(): {
56
+ x: number;
57
+ y: number;
58
+ };
59
+ /**
60
+ * As sRGB, 0–1 per channel at 1000 lm of white (past 1 when brighter). What
61
+ * a screen can't show of it (the bulbs' deepest blues, say) is left out.
62
+ */
63
+ get rgb(): {
64
+ r: number;
65
+ g: number;
66
+ b: number;
67
+ };
68
+ /** As a CSS hex code, "#rrggbb", clipped to what a screen shows. */
69
+ get hex(): string;
70
+ /** As HSL: hue in degrees, saturation and lightness 0–1 (clipped to what a screen shows). */
71
+ get hsl(): {
72
+ h: number;
73
+ s: number;
74
+ l: number;
75
+ };
76
+ /** As OKLab (CSS's: L 0–1, at 1000 lm of white). */
77
+ get oklab(): {
78
+ l: number;
79
+ a: number;
80
+ b: number;
81
+ };
82
+ /** As OKLCh (CSS's: L 0–1 at 1000 lm of white, chroma, hue in degrees). */
83
+ get oklch(): {
84
+ l: number;
85
+ c: number;
86
+ h: number;
87
+ };
88
+ /** The same color at `lm` lumens. */
89
+ at(lm: number): Color;
90
+ /** k times the light: dim(0.5) is half the lumens, dim(2) twice. */
91
+ dim(k: number): Color;
92
+ /** Looks k times as bright: fade(0.5) looks half as bright (an eighth of the lumens). */
93
+ fade(k: number): Color;
94
+ /** With some of it changed: with({ fidelity: 0 }), with({ hue: 200 }), with({ kelvin: 3000 }). */
95
+ with(changes: ColorChanges): Color;
96
+ /**
97
+ * Toward `other` by t (0 is this, 1 is other; 0.5 if not given), evenly as
98
+ * it looks: the color in a straight line through OKLab, brightness by its
99
+ * cube root. To or from dark, only the brightness changes.
100
+ */
101
+ mix(other: ColorInput, t?: number): Color;
102
+ /** This and others shining together: their light added up, as it would be on a wall. */
103
+ add(...others: ColorInput[]): Color;
104
+ /** The hue turned by `degrees`. */
105
+ shiftHue(degrees: number): Color;
106
+ /** k times the chroma: 0 is white, 1 unchanged, 2 twice as saturated. */
107
+ saturate(k: number): Color;
108
+ /** Dimmed, if need be, to what a bulb makes of it (a color bulb, br30, unless told), so it isn't paled. */
109
+ vivid(bulb?: Bulb): Color;
110
+ /** Like "2700 K · 400 lm" or "265° C0.300 · 40 lm"; color() reads it back. */
111
+ toString(): string;
112
+ toJSON(): {
113
+ a: number;
114
+ b: number;
115
+ lm: number;
116
+ fidelity: number;
117
+ };
118
+ }
119
+ /** No light. */
120
+ export declare const off: Color;
121
+ /**
122
+ * Anything that says a color, as a Color (see the top of color.ts), at `lm`
123
+ * lumens if given. Throws, saying why, if it can't tell what color it is.
124
+ */
125
+ export declare function color(input: ColorInput, lm?: number): Color;
126
+ /**
127
+ * A white of this color temperature (2700 K is a warm bulb, 4000 K neutral,
128
+ * 6500 K daylight; the bulbs go as warm as about 1800 K, dimly), at `lm`
129
+ * lumens (1000 if not given). With no temperature, OKLab's own white.
130
+ */
131
+ export declare function white(kelvin?: number | string, lm?: number): Color;
132
+ /**
133
+ * A color in the lights' own terms: hue in degrees (OKLab's: about 30 red,
134
+ * 110 yellow, 145 green, 265 blue, 330 magenta), chroma at full lightness (0
135
+ * white, 0.1 pale, 0.3 strong, up to about 0.8 for the bulbs' violet), and
136
+ * lumens (1000 if not given).
137
+ */
138
+ export declare function lemtone(hue: number, chroma: number, lm?: number, fidelity?: number): Color;
139
+ /** CSS's oklch(): lightness 0–1 (past 1, a percentage), chroma, hue in degrees; L = 1 is 1000 lm of white. */
140
+ export declare function oklch(l: number, c: number, h: number, alpha?: number): Color;
141
+ /** CSS's oklab(): lightness 0–1 (past 1, a percentage), a, b; L = 1 is 1000 lm of white. */
142
+ export declare function oklab(l: number, a: number, b: number, alpha?: number): Color;
143
+ /** sRGB, 0–1 per channel (0–255 if any is past 1), white at 1000 lm. */
144
+ export declare function rgb(r: number, g: number, b: number, alpha?: number): Color;
145
+ /** HSL: hue in degrees, saturation and lightness 0–1 (past 1, percentages), white at 1000 lm. */
146
+ export declare function hsl(h: number, s: number, l: number, alpha?: number): Color;
147
+ /** A CSS hex code ("#f80", "#ff8800", "ff8800cc"), or anything else color() reads. */
148
+ export declare const hex: (code: string) => Color;
149
+ /** A CIE 1931 chromaticity, at `lm` lumens (1000 if not given). */
150
+ export declare function xy(x: number, y: number, lm?: number): Color;
151
+ /** Colors along a line from 0 to 1: palette(x) is the color at x. */
152
+ export interface Palette {
153
+ (x: number): Color;
154
+ readonly stops: readonly Color[];
155
+ /** Where each stop is, 0 to 1. */
156
+ readonly positions: readonly number[];
157
+ }
158
+ /** A palette's stop: a color, or a color at a place, [0.3, "#f80"]. */
159
+ export type Stop = ColorInput | readonly [number, ColorInput];
160
+ /** Whether v is a palette. */
161
+ export declare const isPalette: (v: unknown) => v is Palette;
162
+ /**
163
+ * A palette through these colors (evenly spaced from 0 to 1 unless placed,
164
+ * [0.3, "#f80"]), mixed between them; outside 0–1 it holds the ends.
165
+ * palette(a, b, c) and palette([a, b, c]) are the same.
166
+ */
167
+ export declare function palette(...given: Stop[] | [readonly Stop[]]): Palette;
168
+ /** A palette from anything that says one: a palette, a list of stops, or one color (from dark at 0 to it at 1). */
169
+ export declare function toPalette(v: unknown): Palette;
170
+ /** Palettes to start from, each dark to bright, within what the color bulbs make. */
171
+ export declare const palettes: {
172
+ /** Deep violet, magenta, orange, warm white. */
173
+ dusk: Palette;
174
+ /** Deep blue, teal, pale cyan, cool white. */
175
+ sea: Palette;
176
+ /** Ember red, orange, firelight, warm white. */
177
+ ember: Palette;
178
+ /** Green, teal, violet: northern lights. */
179
+ aurora: Palette;
180
+ };
181
+ /** What a kind of light can make of each color. */
182
+ export interface Bulb {
183
+ /** arclamp's name for it. */
184
+ readonly type: string;
185
+ /** The most lumens it makes of this color before it starts to pale it; 0 past its most saturated. */
186
+ maxLm(c: ColorInput): number;
187
+ /** The most chroma it makes of this hue. */
188
+ edgeOf(hue: number): number;
189
+ /** The color, dimmed if need be to what it makes, so it isn't paled; one more saturated than it makes at all, brought in to the most it does. */
190
+ vivid(c: ColorInput): Color;
191
+ }
192
+ /**
193
+ * The color bulbs (br30), from vibes' model of Walter's solve: asked for more
194
+ * than they can make of a color, they keep the lumens and pale it toward
195
+ * white. A strong blue tops out near 30 lm; whites near 950 at 4000 K, 500 at
196
+ * 2700 K.
197
+ */
198
+ export declare const br30: Bulb;
199
+ //# sourceMappingURL=color.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"color.d.ts","sourceRoot":"","sources":["../src/color.ts"],"names":[],"mappings":"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"}