@roobscoob/vibes 0.0.0-stage → 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.
Files changed (59) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +276 -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 +202 -0
  7. package/dist/color.d.ts.map +1 -0
  8. package/dist/color.js +492 -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 +105 -0
  19. package/dist/here.d.ts.map +1 -0
  20. package/dist/here.js +219 -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 +29 -0
  40. package/dist/sketch.d.ts.map +1 -0
  41. package/dist/sketch.js +141 -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 +590 -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 +272 -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 +172 -0
  59. package/src/spaces.ts +102 -0
package/dist/spaces.js ADDED
@@ -0,0 +1,91 @@
1
+ // The color spaces people know, to and from the light they stand for.
2
+ //
3
+ // They're all screens' spaces, so their brightness is relative to a screen's
4
+ // white. Here that white is a fixed amount of light, 1000 lm (lemtone's
5
+ // brightness 1.0), the same on every light: rgb(1, 1, 1) asks for 1000 lm,
6
+ // and a screen's full blue, #0000ff, for about 72, as dim next to white as on
7
+ // a screen. Everything goes through XYZ (D65, Y = 1 for that white), with the
8
+ // matrices CSS Color 4 uses.
9
+ import { lmsToXyz, mul3, xyzToLms } from "./lemtone.js";
10
+ /** The light a screen's white stands for, in lumens. */
11
+ export const SCREEN_WHITE_LM = 1000;
12
+ // Linear sRGB <-> OKLab's LMS (Björn Ottosson's), so sRGB and OKLab agree exactly.
13
+ const SRGB_LMS = [
14
+ [0.4122214708, 0.5363325363, 0.0514459929],
15
+ [0.2119034982, 0.6806995451, 0.1073969566],
16
+ [0.0883024619, 0.2817188376, 0.6299787005],
17
+ ];
18
+ const LMS_SRGB = [
19
+ [4.0767416621, -3.3077115913, 0.2309699292],
20
+ [-1.2684380046, 2.6097574011, -0.3413193965],
21
+ [-0.0041960863, -0.7034186147, 1.707614701],
22
+ ];
23
+ export const linearSrgbToXyz = (rgb) => lmsToXyz(mul3(SRGB_LMS, rgb));
24
+ export const xyzToLinearSrgb = (X) => mul3(LMS_SRGB, xyzToLms(X));
25
+ /** sRGB's gamma, undone (extended past 0 and 1 the same way both sides, as CSS does). */
26
+ export function decode(v) {
27
+ const x = Math.abs(v);
28
+ return Math.sign(v) * (x <= 0.04045 ? x / 12.92 : ((x + 0.055) / 1.055) ** 2.4);
29
+ }
30
+ /** sRGB's gamma. */
31
+ export function encode(v) {
32
+ const x = Math.abs(v);
33
+ return Math.sign(v) * (x <= 0.0031308 ? 12.92 * x : 1.055 * x ** (1 / 2.4) - 0.055);
34
+ }
35
+ // Linear Display P3 -> XYZ (CSS Color 4).
36
+ const P3_XYZ = [
37
+ [0.48657094864821626, 0.26566769316909294, 0.1982172852343625],
38
+ [0.22897456406974884, 0.6917385218365062, 0.079286914093745],
39
+ [0, 0.045113381858902575, 1.0439443689009757],
40
+ ];
41
+ export const linearP3ToXyz = (rgb) => mul3(P3_XYZ, rgb);
42
+ // CIE Lab and LCh are relative to D50; back to D65 by Bradford (CSS Color 4).
43
+ const D50 = [0.3457 / 0.3585, 1, (1 - 0.3457 - 0.3585) / 0.3585];
44
+ const D50_D65 = [
45
+ [0.955473421488075, -0.02309845494876471, 0.06325924320057072],
46
+ [-0.0283697093338637, 1.0099953980813041, 0.021041441191917323],
47
+ [0.012314014864481998, -0.020507649298898964, 1.330365926242124],
48
+ ];
49
+ export const xyzD50ToXyz = (X) => mul3(D50_D65, X);
50
+ /** CIE Lab (L 0–100) as XYZ (D65). */
51
+ export function labToXyz(L, a, b) {
52
+ const k = 24389 / 27;
53
+ const e = 216 / 24389;
54
+ const f1 = (L + 16) / 116;
55
+ const f0 = a / 500 + f1;
56
+ const f2 = f1 - b / 200;
57
+ const x = f0 ** 3 > e ? f0 ** 3 : (116 * f0 - 16) / k;
58
+ const y = L > k * e ? f1 ** 3 : L / k;
59
+ const z = f2 ** 3 > e ? f2 ** 3 : (116 * f2 - 16) / k;
60
+ return xyzD50ToXyz([x * D50[0], y, z * D50[2]]);
61
+ }
62
+ /** HSL (hue in degrees, saturation and lightness 0–1) as gamma-encoded sRGB (CSS Color 4). */
63
+ export function hslToSrgb(h, s, l) {
64
+ const hue = ((h % 360) + 360) % 360;
65
+ const f = (n) => {
66
+ const k = (n + hue / 30) % 12;
67
+ return l - s * Math.min(l, 1 - l) * Math.max(-1, Math.min(k - 3, 9 - k, 1));
68
+ };
69
+ return [f(0), f(8), f(4)];
70
+ }
71
+ /** HWB (hue in degrees, whiteness and blackness 0–1) as gamma-encoded sRGB (CSS Color 4). */
72
+ export function hwbToSrgb(h, w, b) {
73
+ if (w + b >= 1) {
74
+ const gray = w / (w + b);
75
+ return [gray, gray, gray];
76
+ }
77
+ return hslToSrgb(h, 1, 0.5).map((v) => v * (1 - w - b) + w);
78
+ }
79
+ /** Gamma-encoded sRGB as HSL (CSS Color 4): hue in degrees (0 for grays), saturation and lightness 0–1. */
80
+ export function srgbToHsl(r, g, b) {
81
+ const max = Math.max(r, g, b);
82
+ const min = Math.min(r, g, b);
83
+ const l = (max + min) / 2;
84
+ const d = max - min;
85
+ if (d === 0)
86
+ return { h: 0, s: 0, l };
87
+ const s = l === 0 || l === 1 ? 0 : (max - l) / Math.min(l, 1 - l);
88
+ let h = max === r ? (g - b) / d + (g < b ? 6 : 0) : max === g ? (b - r) / d + 2 : (r - g) / d + 4;
89
+ h *= 60;
90
+ return { h, s, l };
91
+ }
package/package.json CHANGED
@@ -1,6 +1,26 @@
1
1
  {
2
2
  "name": "@roobscoob/vibes",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
6
- }
3
+ "version": "0.2.0",
4
+ "description": "Color, light and time for sketches on the lights at the Recurse Center",
5
+ "keywords": ["lighting", "lemtone", "oklab", "arclamp", "recurse-center"],
6
+ "license": "MIT",
7
+ "author": "Rose Kodsi-Hall",
8
+ "type": "module",
9
+ "sideEffects": false,
10
+ "main": "./dist/index.js",
11
+ "types": "./dist/index.d.ts",
12
+ "exports": {
13
+ ".": {
14
+ "types": "./dist/index.d.ts",
15
+ "default": "./dist/index.js"
16
+ }
17
+ },
18
+ "files": ["dist", "src", "!src/**/*.test.ts"],
19
+ "scripts": {
20
+ "build": "tsc -p tsconfig.build.json",
21
+ "prepack": "npm run build"
22
+ },
23
+ "publishConfig": {
24
+ "access": "public"
25
+ }
26
+ }
package/src/arclamp.ts ADDED
@@ -0,0 +1,36 @@
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
+
6
+ /** Where a light is: millimeters on its floor's plan, from the building's top-left wall corner. */
7
+ export interface Coords {
8
+ mm_x: number;
9
+ mm_y: number;
10
+ floor: number;
11
+ }
12
+
13
+ /** A light as update() is given it. */
14
+ export interface PrevLight {
15
+ id: number;
16
+ /** A color bulb's or panel's a, b, brightness (1.0 = 1000 lm) and fidelity, or an old bulb's on. */
17
+ channels: Record<string, number>;
18
+ tags?: string[] | null;
19
+ /** Null until the light has been placed. */
20
+ coords?: Coords | null;
21
+ /** The rail it hangs on, and how far along it from the rail's start. */
22
+ rail?: { id: string; mm_along: number } | null;
23
+ }
24
+
25
+ export interface Prev {
26
+ initial_time: number;
27
+ lights: PrevLight[];
28
+ }
29
+
30
+ /** The lights to change, and their channels; anything left out keeps its value from below. */
31
+ export interface Out {
32
+ lights: { id: number; channels: Record<string, number> }[];
33
+ }
34
+
35
+ /** arclamp's shader entry point. */
36
+ export type Update = (prev: Prev, nowMs: number, initialMs: number) => Out;