@orangecheck/design 0.25.0 → 0.27.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/dist/tokens.js CHANGED
@@ -7,7 +7,381 @@ var jsxRuntime = require('react/jsx-runtime');
7
7
  var nextThemes = require('next-themes');
8
8
  var lucideReact = require('lucide-react');
9
9
 
10
- // src/tokens/cn.ts
10
+ var __defProp = Object.defineProperty;
11
+ var __getOwnPropNames = Object.getOwnPropertyNames;
12
+ var __esm = (fn, res) => function __init() {
13
+ return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
14
+ };
15
+ var __export = (target, all) => {
16
+ for (var name in all)
17
+ __defProp(target, name, { get: all[name], enumerable: true });
18
+ };
19
+
20
+ // src/tokens/scene-tokens.ts
21
+ function parseColor(value) {
22
+ let m = value.match(/color\(srgb\s+([\d.]+)\s+([\d.]+)\s+([\d.]+)/);
23
+ if (m?.[1] != null && m[2] != null && m[3] != null) {
24
+ return { r: +m[1], g: +m[2], b: +m[3] };
25
+ }
26
+ m = value.match(/rgba?\(\s*([\d.]+)[,\s]+([\d.]+)[,\s]+([\d.]+)/);
27
+ if (m?.[1] != null && m[2] != null && m[3] != null) {
28
+ return { r: +m[1] / 255, g: +m[2] / 255, b: +m[3] / 255 };
29
+ }
30
+ return null;
31
+ }
32
+ function srgbToOklab({ r, g, b }) {
33
+ const lin = (c) => c <= 0.04045 ? c / 12.92 : Math.pow((c + 0.055) / 1.055, 2.4);
34
+ const lr = lin(r);
35
+ const lg = lin(g);
36
+ const lb = lin(b);
37
+ const l = Math.cbrt(0.4122214708 * lr + 0.5363325363 * lg + 0.0514459929 * lb);
38
+ const m = Math.cbrt(0.2119034982 * lr + 0.6806995451 * lg + 0.1073969566 * lb);
39
+ const s = Math.cbrt(0.0883024619 * lr + 0.2817188376 * lg + 0.6299787005 * lb);
40
+ return {
41
+ L: 0.2104542553 * l + 0.793617785 * m - 0.0040720468 * s,
42
+ a: 1.9779984951 * l - 2.428592205 * m + 0.4505937099 * s,
43
+ b: 0.0259040371 * l + 0.7827717662 * m - 0.808675766 * s
44
+ };
45
+ }
46
+ function oklabToSrgb(L, a, bb) {
47
+ const l = Math.pow(L + 0.3963377774 * a + 0.2158037573 * bb, 3);
48
+ const m = Math.pow(L - 0.1055613458 * a - 0.0638541728 * bb, 3);
49
+ const s = Math.pow(L - 0.0894841775 * a - 1.291485548 * bb, 3);
50
+ const lr = 4.0767416621 * l - 3.3077115913 * m + 0.2309699292 * s;
51
+ const lg = -1.2684380046 * l + 2.6097574011 * m - 0.3413193965 * s;
52
+ const lb = -0.0041960863 * l - 0.7034186147 * m + 1.707614701 * s;
53
+ const un = (c) => Math.min(1, Math.max(0, c <= 31308e-7 ? 12.92 * c : 1.055 * Math.pow(c, 1 / 2.4) - 0.055));
54
+ return { r: un(lr), g: un(lg), b: un(lb) };
55
+ }
56
+ function normalizeHue(c, isDark) {
57
+ const { L, a, b } = srgbToOklab(c);
58
+ const C = Math.hypot(a, b);
59
+ const targetL = isDark ? Math.min(0.75, Math.max(0.55, L)) : Math.min(0.95, Math.max(0.82, L + 0.25));
60
+ const scale = C > 1e-6 ? Math.min(C, 0.14) / C : 0;
61
+ return oklabToSrgb(targetL, a * scale, b * scale);
62
+ }
63
+ function readOcSceneTokens(host) {
64
+ if (typeof document === "undefined") return null;
65
+ const probe = document.createElement("div");
66
+ probe.setAttribute("aria-hidden", "true");
67
+ probe.style.cssText = "position:absolute;width:0;height:0;overflow:hidden;pointer-events:none;";
68
+ const cells = SLOTS.map((slot) => {
69
+ const cell = document.createElement("span");
70
+ cell.style.color = `color-mix(in srgb, var(${slot}), var(${slot}))`;
71
+ probe.appendChild(cell);
72
+ return cell;
73
+ });
74
+ host.appendChild(probe);
75
+ try {
76
+ const parsed = cells.map((cell) => parseColor(getComputedStyle(cell).color));
77
+ const [orange, green, blue, violet, background] = parsed;
78
+ if (!orange || !green || !blue || !violet || !background) return null;
79
+ const root = document.documentElement;
80
+ return {
81
+ palette: [orange, green, blue, violet],
82
+ background,
83
+ isDark: root.classList.contains("dark"),
84
+ motionOff: root.getAttribute("data-oc-motion") === "off"
85
+ };
86
+ } finally {
87
+ host.removeChild(probe);
88
+ }
89
+ }
90
+ function subscribeOcTheme(cb) {
91
+ if (typeof document === "undefined") return () => {
92
+ };
93
+ let raf1 = 0;
94
+ let raf2 = 0;
95
+ const schedule = () => {
96
+ cancelAnimationFrame(raf1);
97
+ cancelAnimationFrame(raf2);
98
+ raf1 = requestAnimationFrame(() => {
99
+ raf2 = requestAnimationFrame(cb);
100
+ });
101
+ };
102
+ const mo = new MutationObserver(schedule);
103
+ mo.observe(document.documentElement, {
104
+ attributes: true,
105
+ attributeFilter: ["class", "data-oc-theme", "data-oc-motion"]
106
+ });
107
+ return () => {
108
+ mo.disconnect();
109
+ cancelAnimationFrame(raf1);
110
+ cancelAnimationFrame(raf2);
111
+ };
112
+ }
113
+ var SLOTS;
114
+ var init_scene_tokens = __esm({
115
+ "src/tokens/scene-tokens.ts"() {
116
+ SLOTS = ["--au-orange", "--au-green", "--au-blue", "--au-violet", "--background"];
117
+ }
118
+ });
119
+
120
+ // src/tokens/aurora-gl.ts
121
+ var aurora_gl_exports = {};
122
+ __export(aurora_gl_exports, {
123
+ mountAuroraGL: () => mountAuroraGL
124
+ });
125
+ function killFlagged() {
126
+ try {
127
+ const raw = localStorage.getItem(KILL_KEY);
128
+ if (!raw) return false;
129
+ if (Date.now() - Number(raw) > KILL_TTL_MS) {
130
+ localStorage.removeItem(KILL_KEY);
131
+ return false;
132
+ }
133
+ return true;
134
+ } catch {
135
+ return false;
136
+ }
137
+ }
138
+ function setKillFlag() {
139
+ try {
140
+ localStorage.setItem(KILL_KEY, String(Date.now()));
141
+ } catch {
142
+ }
143
+ }
144
+ function cypherFinish() {
145
+ const skin = document.documentElement.getAttribute("data-oc-theme");
146
+ return skin !== null && skin !== "ember";
147
+ }
148
+ function samplePalette(host) {
149
+ const tokens = readOcSceneTokens(host);
150
+ if (!tokens) return null;
151
+ return {
152
+ hues: tokens.palette.map((h) => normalizeHue(h, tokens.isDark)),
153
+ bg: tokens.background,
154
+ isDark: tokens.isDark,
155
+ finish: cypherFinish() ? 1 : 0
156
+ };
157
+ }
158
+ function mountAuroraGL(container) {
159
+ if (killFlagged()) return null;
160
+ if (getComputedStyle(container).getPropertyValue("--oc-aurora-gl").trim() === "off") {
161
+ return null;
162
+ }
163
+ const canvas = document.createElement("canvas");
164
+ canvas.className = "oc-aurora__gl";
165
+ const glMaybe = canvas.getContext("webgl2", {
166
+ antialias: false,
167
+ depth: false,
168
+ stencil: false,
169
+ alpha: false,
170
+ powerPreference: "low-power",
171
+ failIfMajorPerformanceCaveat: true
172
+ // SwiftShader/blocklist → CSS floor, free
173
+ });
174
+ if (!glMaybe) return null;
175
+ const gl = glMaybe;
176
+ const first = samplePalette(container);
177
+ if (!first) return null;
178
+ let prog;
179
+ const uni = {};
180
+ try {
181
+ const compile = (type, src) => {
182
+ const s = gl.createShader(type);
183
+ gl.shaderSource(s, src);
184
+ gl.compileShader(s);
185
+ if (!gl.getShaderParameter(s, gl.COMPILE_STATUS)) throw new Error("compile");
186
+ return s;
187
+ };
188
+ prog = gl.createProgram();
189
+ gl.attachShader(prog, compile(gl.VERTEX_SHADER, VS));
190
+ gl.attachShader(prog, compile(gl.FRAGMENT_SHADER, FS));
191
+ gl.linkProgram(prog);
192
+ if (!gl.getProgramParameter(prog, gl.LINK_STATUS)) throw new Error("link");
193
+ gl.useProgram(prog);
194
+ const buf = gl.createBuffer();
195
+ gl.bindBuffer(gl.ARRAY_BUFFER, buf);
196
+ gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([-1, -1, 3, -1, -1, 3]), gl.STATIC_DRAW);
197
+ const loc = gl.getAttribLocation(prog, "p");
198
+ gl.enableVertexAttribArray(loc);
199
+ gl.vertexAttribPointer(loc, 2, gl.FLOAT, false, 0, 0);
200
+ for (const k of ["uRes", "uT", "uIsDark", "uFinish", "uMix", "uA0", "uA1", "uA2", "uA3", "uB0", "uB1", "uB2", "uB3", "uBg"]) {
201
+ uni[k] = gl.getUniformLocation(prog, k);
202
+ }
203
+ } catch {
204
+ return null;
205
+ }
206
+ container.appendChild(canvas);
207
+ let palFrom = first;
208
+ let palTo = first;
209
+ let mixStart = 0;
210
+ let raf = 0;
211
+ let lastFrame = 0;
212
+ let clock = 0;
213
+ let lastTick = 0;
214
+ let lastInput = performance.now();
215
+ let live = false;
216
+ let disposed = false;
217
+ let slowStreak = 0;
218
+ const setVec = (k, c) => gl.uniform3f(uni[k] ?? null, c.r, c.g, c.b);
219
+ function resize() {
220
+ const coarse = matchMedia("(pointer: coarse)").matches;
221
+ const dpr = Math.min(devicePixelRatio || 1, coarse ? 1.5 : 2) * 0.75;
222
+ const w = Math.max(1, Math.round(container.clientWidth * dpr));
223
+ const hgt = Math.max(1, Math.round(container.clientHeight * dpr));
224
+ if (canvas.width !== w || canvas.height !== hgt) {
225
+ canvas.width = w;
226
+ canvas.height = hgt;
227
+ gl.viewport(0, 0, w, hgt);
228
+ }
229
+ }
230
+ function draw(now) {
231
+ raf = requestAnimationFrame(draw);
232
+ if (now - lastFrame < FRAME_MS) return;
233
+ const frameGap = now - lastFrame;
234
+ lastFrame = now;
235
+ if (frameGap > FRAME_MS * 2.5) {
236
+ if (++slowStreak > 90) {
237
+ setKillFlag();
238
+ dispose();
239
+ return;
240
+ }
241
+ } else if (slowStreak > 0) slowStreak--;
242
+ const settled = now - lastInput > SETTLE_MS;
243
+ if (!settled) {
244
+ clock += Math.min(now - lastTick, 100) / 1e3;
245
+ }
246
+ lastTick = now;
247
+ if (settled && live && mixDone(now)) return;
248
+ resize();
249
+ const mix = Math.min(1, (now - mixStart) / CROSSFADE_MS);
250
+ gl.uniform2f(uni.uRes ?? null, canvas.width, canvas.height);
251
+ gl.uniform1f(uni.uT ?? null, clock);
252
+ gl.uniform1f(uni.uIsDark ?? null, palTo.isDark ? 1 : 0);
253
+ gl.uniform1f(uni.uFinish ?? null, palTo.finish);
254
+ gl.uniform1f(uni.uMix ?? null, mix);
255
+ setVec("uA0", palFrom.hues[0]);
256
+ setVec("uA1", palFrom.hues[1]);
257
+ setVec("uA2", palFrom.hues[2]);
258
+ setVec("uA3", palFrom.hues[3]);
259
+ setVec("uB0", palTo.hues[0]);
260
+ setVec("uB1", palTo.hues[1]);
261
+ setVec("uB2", palTo.hues[2]);
262
+ setVec("uB3", palTo.hues[3]);
263
+ setVec("uBg", palTo.bg);
264
+ gl.drawArrays(gl.TRIANGLES, 0, 3);
265
+ if (!live) {
266
+ live = true;
267
+ container.classList.add("oc-aurora--gl-live");
268
+ }
269
+ }
270
+ function mixDone(now) {
271
+ return now - mixStart >= CROSSFADE_MS;
272
+ }
273
+ const onInput = () => {
274
+ lastInput = performance.now();
275
+ };
276
+ const onVisibility = () => {
277
+ if (document.hidden) {
278
+ cancelAnimationFrame(raf);
279
+ raf = 0;
280
+ } else if (!raf && !disposed) {
281
+ lastFrame = 0;
282
+ lastTick = performance.now();
283
+ raf = requestAnimationFrame(draw);
284
+ }
285
+ };
286
+ const onContextLost = (e) => {
287
+ e.preventDefault();
288
+ cancelAnimationFrame(raf);
289
+ raf = 0;
290
+ };
291
+ const onContextRestored = () => {
292
+ dispose();
293
+ };
294
+ const unsubscribeTheme = subscribeOcTheme(() => {
295
+ if (disposed) return;
296
+ const root = document.documentElement;
297
+ if (root.getAttribute("data-oc-motion") === "off") {
298
+ dispose();
299
+ return;
300
+ }
301
+ const next = samplePalette(container);
302
+ if (!next) return;
303
+ palFrom = { ...palTo, hues: [...palTo.hues] };
304
+ palTo = next;
305
+ mixStart = performance.now();
306
+ lastInput = performance.now();
307
+ });
308
+ window.addEventListener("pointermove", onInput, { passive: true });
309
+ window.addEventListener("scroll", onInput, { passive: true });
310
+ window.addEventListener("keydown", onInput, { passive: true });
311
+ document.addEventListener("visibilitychange", onVisibility);
312
+ canvas.addEventListener("webglcontextlost", onContextLost);
313
+ canvas.addEventListener("webglcontextrestored", onContextRestored);
314
+ function dispose() {
315
+ if (disposed) return;
316
+ disposed = true;
317
+ cancelAnimationFrame(raf);
318
+ unsubscribeTheme();
319
+ window.removeEventListener("pointermove", onInput);
320
+ window.removeEventListener("scroll", onInput);
321
+ window.removeEventListener("keydown", onInput);
322
+ document.removeEventListener("visibilitychange", onVisibility);
323
+ canvas.removeEventListener("webglcontextlost", onContextLost);
324
+ canvas.removeEventListener("webglcontextrestored", onContextRestored);
325
+ container.classList.remove("oc-aurora--gl-live");
326
+ canvas.remove();
327
+ const ext = gl.getExtension("WEBGL_lose_context");
328
+ if (ext) ext.loseContext();
329
+ }
330
+ resize();
331
+ mixStart = performance.now();
332
+ lastTick = performance.now();
333
+ raf = requestAnimationFrame(draw);
334
+ return dispose;
335
+ }
336
+ var KILL_KEY, KILL_TTL_MS, SETTLE_MS, FRAME_MS, CROSSFADE_MS, VS, FS;
337
+ var init_aurora_gl = __esm({
338
+ "src/tokens/aurora-gl.ts"() {
339
+ init_scene_tokens();
340
+ KILL_KEY = "oc-aurora-gl-kill:1";
341
+ KILL_TTL_MS = 7 * 24 * 60 * 60 * 1e3;
342
+ SETTLE_MS = 9e4;
343
+ FRAME_MS = 33;
344
+ CROSSFADE_MS = 250;
345
+ VS = `#version 300 es
346
+ in vec2 p;void main(){gl_Position=vec4(p,0.,1.);}`;
347
+ FS = `#version 300 es
348
+ precision highp float;
349
+ out vec4 o;
350
+ uniform vec2 uRes;uniform float uT,uIsDark,uFinish,uMix;
351
+ uniform vec3 uA0,uA1,uA2,uA3,uB0,uB1,uB2,uB3,uBg;
352
+ float h(vec2 p){return fract(sin(dot(p,vec2(127.1,311.7)))*43758.5453);}
353
+ float n2(vec2 p){vec2 i=floor(p),f=fract(p);f=f*f*(3.-2.*f);
354
+ return mix(mix(h(i),h(i+vec2(1,0)),f.x),mix(h(i+vec2(0,1)),h(i+vec2(1,1)),f.x),f.y);}
355
+ float fbm(vec2 p){float v=0.,a=.55;for(int i=0;i<3;i++){v+=a*n2(p);p=p*2.03+vec2(1.7,9.2);a*=.5;}return v;}
356
+ float B2(vec2 a){a=floor(a);return fract(a.x/2.+a.y*a.y*.75);}
357
+ // OKLab mix (Ottosson) so skin crossfades never transit gray-brown.
358
+ vec3 l2s(vec3 c){return mix(12.92*c,1.055*pow(c,vec3(1./2.4))-.055,step(.0031308,c));}
359
+ vec3 s2l(vec3 c){return mix(c/12.92,pow((c+.055)/1.055,vec3(2.4)),step(.04045,c));}
360
+ vec3 okmix(vec3 a,vec3 b,float t){
361
+ vec3 la=s2l(a),lb=s2l(b);
362
+ mat3 M1=mat3(.4122214708,.2119034982,.0883024619,.5363325363,.6806995451,.2817188376,.0514459929,.1073969566,.6299787005);
363
+ mat3 M2=mat3(4.0767416621,-1.2684380046,-.0041960863,-3.3077115913,2.6097574011,-.7034186147,.2309699292,-.3413193965,1.707614701);
364
+ vec3 ka=pow(M1*la,vec3(1./3.)),kb=pow(M1*lb,vec3(1./3.));
365
+ vec3 k=mix(ka,kb,t);return clamp(l2s(M2*(k*k*k)),0.,1.);}
366
+ void main(){
367
+ vec2 uv=gl_FragCoord.xy/uRes;
368
+ vec2 p=(uv-.5)*vec2(uRes.x/uRes.y,1.)*1.9;
369
+ float t=uT*.018;
370
+ vec2 w=vec2(fbm(p+vec2(0.,t)),fbm(p+vec2(5.2,1.3)-t*.7));
371
+ float f=fbm(p+1.9*w+vec2(t*.5,-t*.3));
372
+ float g=fbm(p*.6+w*1.2+vec2(9.1,3.7));
373
+ vec3 c0=okmix(uA0,uB0,uMix),c1=okmix(uA1,uB1,uMix),c2=okmix(uA2,uB2,uMix),c3=okmix(uA3,uB3,uMix);
374
+ vec3 c=mix(mix(c0,c1,smoothstep(.25,.55,g)),mix(c2,c3,smoothstep(.45,.8,g)),smoothstep(.4,.7,g));
375
+ float e=smoothstep(.32,.9,f);
376
+ if(uFinish>.5){
377
+ float b=B2(.125*gl_FragCoord.xy)*.0625+B2(.25*gl_FragCoord.xy)*.25+B2(.5*gl_FragCoord.xy);
378
+ e=floor(e*5.+b*.8-.4)/5.;}
379
+ // container CSS already applies the mode-op \xD7 intensity opacity + radial mask
380
+ vec3 col=(uIsDark>.5)?clamp(uBg+c*e*1.15,0.,1.):mix(uBg,c,e);
381
+ col+=(fract(52.9829189*fract(dot(gl_FragCoord.xy,vec2(0.06711056,0.00583715))))-.5)/255.;
382
+ o=vec4(col,1.);}`;
383
+ }
384
+ });
11
385
  function cn(...inputs) {
12
386
  return tailwindMerge.twMerge(clsx.clsx(inputs));
13
387
  }
@@ -57,13 +431,85 @@ function resolveTheme(id) {
57
431
  return isKnownTheme(id) ? id : DEFAULT_OC_THEME;
58
432
  }
59
433
  var OC_SKIN_COOKIE = "oc_skin";
434
+ var OC_MOTION_COOKIE = "oc_motion";
60
435
  var BLOBS = [1, 2, 3, 4, 5];
61
- function OcAurora({ intensity, className }) {
436
+ function onIdle(cb, timeout) {
437
+ if (typeof requestIdleCallback === "function") {
438
+ const id2 = requestIdleCallback(cb, { timeout });
439
+ return () => cancelIdleCallback(id2);
440
+ }
441
+ const id = setTimeout(cb, timeout);
442
+ return () => clearTimeout(id);
443
+ }
444
+ function OcAurora({ intensity, gl = false, className }) {
445
+ const hostRef = react.useRef(null);
446
+ react.useEffect(() => {
447
+ if (!gl) return;
448
+ const host = hostRef.current;
449
+ if (!host) return;
450
+ let disposed = false;
451
+ let disposeScene = null;
452
+ let cancelIdle = null;
453
+ const prm = matchMedia("(prefers-reduced-motion: reduce)");
454
+ const forced = matchMedia("(forced-colors: active)");
455
+ function gatesPass() {
456
+ if (prm.matches || forced.matches) return false;
457
+ if (document.documentElement.getAttribute("data-oc-motion") === "off") return false;
458
+ const nav = navigator;
459
+ if (nav.connection?.saveData === true) return false;
460
+ if (typeof nav.deviceMemory === "number" && nav.deviceMemory <= 4) return false;
461
+ return true;
462
+ }
463
+ function boot() {
464
+ cancelIdle = onIdle(async () => {
465
+ if (disposed || disposeScene || !gatesPass()) return;
466
+ try {
467
+ const mod = await Promise.resolve().then(() => (init_aurora_gl(), aurora_gl_exports));
468
+ if (disposed || disposeScene || !gatesPass()) return;
469
+ disposeScene = mod.mountAuroraGL(host);
470
+ } catch {
471
+ }
472
+ }, 2e3);
473
+ }
474
+ function teardownScene() {
475
+ disposeScene?.();
476
+ disposeScene = null;
477
+ }
478
+ const onPrmChange = () => {
479
+ if (prm.matches) teardownScene();
480
+ else if (!disposeScene) boot();
481
+ };
482
+ prm.addEventListener?.("change", onPrmChange);
483
+ const mo = new MutationObserver(() => {
484
+ const off = document.documentElement.getAttribute("data-oc-motion") === "off";
485
+ if (!off && !disposeScene && !disposed) boot();
486
+ });
487
+ mo.observe(document.documentElement, {
488
+ attributes: true,
489
+ attributeFilter: ["data-oc-motion"]
490
+ });
491
+ if (document.readyState === "complete") boot();
492
+ else {
493
+ const onLoad = () => boot();
494
+ window.addEventListener("load", onLoad, { once: true });
495
+ }
496
+ return () => {
497
+ disposed = true;
498
+ cancelIdle?.();
499
+ prm.removeEventListener?.("change", onPrmChange);
500
+ mo.disconnect();
501
+ teardownScene();
502
+ };
503
+ }, [gl]);
62
504
  const style = intensity == null ? void 0 : { "--oc-aurora-intensity": String(intensity) };
63
- return /* @__PURE__ */ jsxRuntime.jsx("div", { className: cn("oc-aurora", className), style, "aria-hidden": "true", children: BLOBS.map((n) => /* @__PURE__ */ jsxRuntime.jsx("div", { className: `oc-aurora__blob oc-aurora__blob-${n}` }, n)) });
505
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { ref: hostRef, className: cn("oc-aurora", className), style, "aria-hidden": "true", children: [
506
+ BLOBS.map((n) => /* @__PURE__ */ jsxRuntime.jsx("div", { className: `oc-aurora__blob oc-aurora__blob-${n}` }, n)),
507
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "oc-aurora__grain" })
508
+ ] });
64
509
  }
65
510
  var ONE_YEAR = 60 * 60 * 24 * 365;
66
511
  var ATTR = "data-oc-theme";
512
+ var MOTION_ATTR = "data-oc-motion";
67
513
  function readSkinCookie() {
68
514
  if (typeof document === "undefined") return null;
69
515
  const prefix = `${OC_SKIN_COOKIE}=`;
@@ -95,6 +541,38 @@ function applyAttr(skin) {
95
541
  if (typeof document === "undefined") return;
96
542
  document.documentElement.setAttribute(ATTR, skin);
97
543
  }
544
+ function readMotionCookie() {
545
+ if (typeof document === "undefined") return null;
546
+ const prefix = `${OC_MOTION_COOKIE}=`;
547
+ for (const part of document.cookie.split(";")) {
548
+ const trimmed = part.trim();
549
+ if (trimmed.startsWith(prefix)) {
550
+ const v = decodeURIComponent(trimmed.slice(prefix.length));
551
+ return v === "off" ? "off" : v === "on" ? "on" : null;
552
+ }
553
+ }
554
+ return null;
555
+ }
556
+ function writeMotionCookie(value) {
557
+ if (typeof document === "undefined") return;
558
+ const isLocal = location.hostname === "localhost" || location.hostname === "127.0.0.1";
559
+ const parts = [
560
+ `${OC_MOTION_COOKIE}=${encodeURIComponent(value)}`,
561
+ "Path=/",
562
+ `Max-Age=${ONE_YEAR}`,
563
+ "SameSite=Lax"
564
+ ];
565
+ if (!isLocal) {
566
+ parts.push("Domain=.ochk.io");
567
+ parts.push("Secure");
568
+ }
569
+ document.cookie = parts.join("; ");
570
+ }
571
+ function applyMotionAttr(motion) {
572
+ if (typeof document === "undefined") return;
573
+ if (motion === "off") document.documentElement.setAttribute(MOTION_ATTR, "off");
574
+ else document.documentElement.removeAttribute(MOTION_ATTR);
575
+ }
98
576
  function applySkinChrome(skin) {
99
577
  if (typeof window === "undefined") return;
100
578
  if (typeof window.__ocApplySkinChrome === "function") {
@@ -111,6 +589,7 @@ function OcThemeProvider({
111
589
  aurora = true
112
590
  }) {
113
591
  const [skin, setSkinState] = react.useState(() => resolveTheme(defaultSkin));
592
+ const [motion, setMotionState] = react.useState("on");
114
593
  const hydratedRef = react.useRef(false);
115
594
  react.useEffect(() => {
116
595
  if (hydratedRef.current) return;
@@ -119,6 +598,9 @@ function OcThemeProvider({
119
598
  applyAttr(fromCookie);
120
599
  applySkinChrome(fromCookie);
121
600
  setSkinState(fromCookie);
601
+ const motionCookie = readMotionCookie() ?? "on";
602
+ applyMotionAttr(motionCookie);
603
+ setMotionState(motionCookie);
122
604
  }, [defaultSkin]);
123
605
  react.useEffect(() => {
124
606
  function sync() {
@@ -128,6 +610,11 @@ function OcThemeProvider({
128
610
  applySkinChrome(fromCookie);
129
611
  setSkinState(fromCookie);
130
612
  }
613
+ const motionCookie = readMotionCookie() ?? "on";
614
+ if (motionCookie !== motion) {
615
+ applyMotionAttr(motionCookie);
616
+ setMotionState(motionCookie);
617
+ }
131
618
  }
132
619
  window.addEventListener("focus", sync);
133
620
  document.addEventListener("visibilitychange", sync);
@@ -135,7 +622,7 @@ function OcThemeProvider({
135
622
  window.removeEventListener("focus", sync);
136
623
  document.removeEventListener("visibilitychange", sync);
137
624
  };
138
- }, [skin]);
625
+ }, [skin, motion]);
139
626
  const setSkin = react.useCallback((id) => {
140
627
  const next = resolveTheme(id);
141
628
  applyAttr(next);
@@ -143,12 +630,24 @@ function OcThemeProvider({
143
630
  writeSkinCookie(next);
144
631
  setSkinState(next);
145
632
  }, []);
633
+ const setMotion = react.useCallback((value2) => {
634
+ const next = value2 === "off" ? "off" : "on";
635
+ applyMotionAttr(next);
636
+ writeMotionCookie(next);
637
+ setMotionState(next);
638
+ }, []);
146
639
  const value = react.useMemo(
147
- () => ({ skin, setSkin, themes: OC_THEMES }),
148
- [skin, setSkin]
640
+ () => ({ skin, setSkin, themes: OC_THEMES, motion, setMotion }),
641
+ [skin, setSkin, motion, setMotion]
149
642
  );
150
643
  return /* @__PURE__ */ jsxRuntime.jsxs(OcSkinContext.Provider, { value, children: [
151
- aurora !== false && /* @__PURE__ */ jsxRuntime.jsx(OcAurora, { intensity: typeof aurora === "object" ? aurora.intensity : void 0 }),
644
+ aurora !== false && /* @__PURE__ */ jsxRuntime.jsx(
645
+ OcAurora,
646
+ {
647
+ intensity: typeof aurora === "object" ? aurora.intensity : void 0,
648
+ gl: typeof aurora === "object" ? aurora.gl : void 0
649
+ }
650
+ ),
152
651
  children
153
652
  ] });
154
653
  }
@@ -159,9 +658,13 @@ function useOcSkin() {
159
658
  }
160
659
  return ctx;
161
660
  }
661
+ function useOcMotion() {
662
+ const { motion, setMotion } = useOcSkin();
663
+ return { motion, setMotion };
664
+ }
162
665
  function getOcThemeInitScript(defaultSkin = DEFAULT_OC_THEME) {
163
666
  const accents = Object.fromEntries(OC_THEMES.map((t) => [t.id, t.accent]));
164
- return `(function(){var ACC=${JSON.stringify(accents)},DEF=${JSON.stringify(defaultSkin)},ORIG=${JSON.stringify(OC_DEFAULT_ACCENT)},fav=null;function acc(s){return ACC[s]||ACC[DEF]||ORIG;}window.__ocApplySkinChrome=function(s){try{var a=acc(s);var meta=document.querySelector('meta[name="theme-color"]');if(meta){meta.setAttribute('content',a);}var link=document.querySelector('link[rel~="icon"][type="image/svg+xml"]');if(!link){return;}var paint=function(svg){link.setAttribute('href','data:image/svg+xml,'+encodeURIComponent(svg.split(ORIG).join(a)));};if(fav!=null){paint(fav);return;}var h=link.getAttribute('href');if(!h||h.indexOf('data:')===0){return;}fetch(h).then(function(r){return r.text();}).then(function(svg){fav=svg;paint(svg);}).catch(function(){});}catch(e){}};try{var m=document.cookie.match(/(?:^|; )${OC_SKIN_COOKIE}=([^;]*)/);var s=m?decodeURIComponent(m[1]):DEF;if(!s){s=DEF;}document.documentElement.setAttribute('${ATTR}',s);window.__ocApplySkinChrome(s);}catch(e){document.documentElement.setAttribute('${ATTR}',DEF);}})();`;
667
+ return `(function(){var ACC=${JSON.stringify(accents)},DEF=${JSON.stringify(defaultSkin)},ORIG=${JSON.stringify(OC_DEFAULT_ACCENT)},fav=null;function acc(s){return ACC[s]||ACC[DEF]||ORIG;}window.__ocApplySkinChrome=function(s){try{var a=acc(s);var meta=document.querySelector('meta[name="theme-color"]');if(meta){meta.setAttribute('content',a);}var link=document.querySelector('link[rel~="icon"][type="image/svg+xml"]');if(!link){return;}var paint=function(svg){link.setAttribute('href','data:image/svg+xml,'+encodeURIComponent(svg.split(ORIG).join(a)));};if(fav!=null){paint(fav);return;}var h=link.getAttribute('href');if(!h||h.indexOf('data:')===0){return;}fetch(h).then(function(r){return r.text();}).then(function(svg){fav=svg;paint(svg);}).catch(function(){});}catch(e){}};try{var m=document.cookie.match(/(?:^|; )${OC_SKIN_COOKIE}=([^;]*)/);var s=m?decodeURIComponent(m[1]):DEF;if(!s){s=DEF;}document.documentElement.setAttribute('${ATTR}',s);window.__ocApplySkinChrome(s);}catch(e){document.documentElement.setAttribute('${ATTR}',DEF);}try{var mm=document.cookie.match(/(?:^|; )${OC_MOTION_COOKIE}=([^;]*)/);if(mm&&decodeURIComponent(mm[1])==='off'){document.documentElement.setAttribute('${MOTION_ATTR}','off');}}catch(e){}})();`;
165
668
  }
166
669
  var COOKIE = "oc_theme";
167
670
  var ALLOWED = /* @__PURE__ */ new Set(["light", "dark", "system"]);
@@ -296,10 +799,12 @@ var MODES = [
296
799
  ];
297
800
  function AppearanceControls({ className }) {
298
801
  const { skin, setSkin, themes } = useOcSkin();
802
+ const { motion, setMotion } = useOcMotion();
299
803
  const { theme, setTheme } = nextThemes.useTheme();
300
804
  const [mounted, setMounted] = react.useState(false);
301
805
  react.useEffect(() => setMounted(true), []);
302
806
  const activeMode = mounted ? theme ?? "system" : null;
807
+ const activeMotion = mounted ? motion : null;
303
808
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { className, children: [
304
809
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "label-mono text-muted-foreground px-3 pt-3 pb-2", children: "mode" }),
305
810
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "grid grid-cols-3 gap-1 px-2 pb-2", children: MODES.map(({ id, label, Icon }) => {
@@ -346,6 +851,32 @@ function AppearanceControls({ className }) {
346
851
  ]
347
852
  }
348
853
  ) }, t.id);
854
+ }) }),
855
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "label-mono text-muted-foreground border-t px-3 pt-3 pb-2", children: "ambient motion" }),
856
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "grid grid-cols-2 gap-1 px-2 pb-3", children: [
857
+ { id: "on", label: "on", Icon: lucideReact.Waves },
858
+ { id: "off", label: "off", Icon: lucideReact.Pause }
859
+ ].map(({ id, label, Icon }) => {
860
+ const active = activeMotion === id;
861
+ return /* @__PURE__ */ jsxRuntime.jsxs(
862
+ "button",
863
+ {
864
+ type: "button",
865
+ role: "menuitemradio",
866
+ "aria-checked": active,
867
+ "aria-label": id === "off" ? "pause ambient motion" : "ambient motion on",
868
+ onClick: () => setMotion(id),
869
+ className: cn(
870
+ "flex flex-col items-center gap-1 rounded-md border py-2 text-[11px] transition-colors",
871
+ active ? "border-primary text-foreground bg-accent" : "border-transparent text-muted-foreground hover:bg-accent hover:text-accent-foreground"
872
+ ),
873
+ children: [
874
+ /* @__PURE__ */ jsxRuntime.jsx(Icon, { className: "size-4", "aria-hidden": true }),
875
+ label
876
+ ]
877
+ },
878
+ id
879
+ );
349
880
  }) })
350
881
  ] });
351
882
  }
@@ -402,9 +933,13 @@ function OcAppearanceMenu({
402
933
  ] });
403
934
  }
404
935
 
936
+ // src/tokens/index.ts
937
+ init_scene_tokens();
938
+
405
939
  exports.AppearanceControls = AppearanceControls;
406
940
  exports.DEFAULT_OC_THEME = DEFAULT_OC_THEME;
407
941
  exports.OC_DEFAULT_ACCENT = OC_DEFAULT_ACCENT;
942
+ exports.OC_MOTION_COOKIE = OC_MOTION_COOKIE;
408
943
  exports.OC_SKIN_COOKIE = OC_SKIN_COOKIE;
409
944
  exports.OC_THEMES = OC_THEMES;
410
945
  exports.OcAppearanceMenu = OcAppearanceMenu;
@@ -416,7 +951,11 @@ exports.accentFor = accentFor;
416
951
  exports.cn = cn;
417
952
  exports.getOcThemeInitScript = getOcThemeInitScript;
418
953
  exports.isKnownTheme = isKnownTheme;
954
+ exports.normalizeHue = normalizeHue;
955
+ exports.readOcSceneTokens = readOcSceneTokens;
419
956
  exports.resolveTheme = resolveTheme;
957
+ exports.subscribeOcTheme = subscribeOcTheme;
958
+ exports.useOcMotion = useOcMotion;
420
959
  exports.useOcSkin = useOcSkin;
421
960
  //# sourceMappingURL=tokens.js.map
422
961
  //# sourceMappingURL=tokens.js.map