@juspay/svelte-ui-components 4.33.0 → 4.33.2
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/ThinkingOrb/ThinkingOrb.svelte +51 -38
- package/dist/ThinkingOrb/orb/modes/form.js +21 -10
- package/dist/ThinkingOrb/orb/modes/network.d.ts +1 -1
- package/dist/ThinkingOrb/orb/modes/network.js +60 -45
- package/dist/ThinkingOrb/orb/modes/sphere.js +119 -26
- package/dist/ThinkingOrb/orb/paint.d.ts +15 -10
- package/dist/ThinkingOrb/orb/paint.js +19 -19
- package/dist/ThinkingOrb/orb/space.d.ts +7 -2
- package/dist/ThinkingOrb/orb/space.js +3 -1
- package/dist-wc/index.js +147 -106
- package/package.json +1 -1
|
@@ -61,20 +61,19 @@
|
|
|
61
61
|
/*
|
|
62
62
|
* `reducedMotion`/`onScreen`/`tabVisible` feed `shouldRun` below (a
|
|
63
63
|
* `$derived`), so they must be real `$state` for it to react when they
|
|
64
|
-
* change. `
|
|
65
|
-
*
|
|
66
|
-
*
|
|
67
|
-
*
|
|
68
|
-
*
|
|
69
|
-
*
|
|
70
|
-
*
|
|
71
|
-
* the
|
|
72
|
-
*
|
|
64
|
+
* change. `pointer` is a plain `let`, not `$state`: a still orb repaints
|
|
65
|
+
* explicitly on pointer events (see `repaintIfStill`), and a running orb's
|
|
66
|
+
* loop already reads the latest pointer every tick, so retriggering the
|
|
67
|
+
* whole effect on every pointer move would only tear down and restart the
|
|
68
|
+
* loop for nothing. A theme change works the same way: a still orb
|
|
69
|
+
* repaints explicitly (see `repaintIfColorChanged`) once its *resolved*
|
|
70
|
+
* colour actually moves, rather than through a theme-flavoured state write
|
|
71
|
+
* -- the paint never needs to know the theme itself, only the colour it
|
|
72
|
+
* comes out to.
|
|
73
73
|
*/
|
|
74
74
|
let reducedMotion = $state(prefersReducedMotion());
|
|
75
75
|
let onScreen = $state(true);
|
|
76
76
|
let tabVisible = $state(true);
|
|
77
|
-
let dark = $state(false);
|
|
78
77
|
let announcedFirstFrame = false;
|
|
79
78
|
let resolvedColorInput = '';
|
|
80
79
|
let resolvedTint: Rgb = FALLBACK_TINT;
|
|
@@ -150,6 +149,22 @@
|
|
|
150
149
|
draw(heldInstant());
|
|
151
150
|
};
|
|
152
151
|
|
|
152
|
+
/** A still orb repaints only when its resolved colour actually changed --
|
|
153
|
+
* whatever mechanism the host used to flip theme (an attribute on `<html>`
|
|
154
|
+
* or `<body>`, or a CSS transition landing). An explicit `color` prop
|
|
155
|
+
* never depends on the theme, and a running orb already re-reads the
|
|
156
|
+
* colour every frame via `draw`, so both bail out here. `readColorInput`'s
|
|
157
|
+
* cached key is what `resolveTint` itself compares against, so this check
|
|
158
|
+
* and the eventual repaint can never disagree about whether anything moved. */
|
|
159
|
+
const repaintIfColorChanged = (): void => {
|
|
160
|
+
if (shouldRun || color || canvas === null) {
|
|
161
|
+
return;
|
|
162
|
+
}
|
|
163
|
+
if (readColorInput(canvas).key !== resolvedColorInput) {
|
|
164
|
+
draw(heldInstant());
|
|
165
|
+
}
|
|
166
|
+
};
|
|
167
|
+
|
|
153
168
|
const trackPointer = (event: PointerEvent): void => {
|
|
154
169
|
if (canvas === null || !gravity) {
|
|
155
170
|
return;
|
|
@@ -196,7 +211,7 @@
|
|
|
196
211
|
const frame = MODES[safeState](instant, { size: safeSize, density, dotScale });
|
|
197
212
|
const gOpts = gravityOptions;
|
|
198
213
|
const painted = gOpts === null ? frame : attract(frame, pointer, gOpts);
|
|
199
|
-
paintFrame(context, painted, {
|
|
214
|
+
paintFrame(context, painted, { tint: resolveTint(context) });
|
|
200
215
|
|
|
201
216
|
if (!announcedFirstFrame) {
|
|
202
217
|
announcedFirstFrame = true;
|
|
@@ -206,7 +221,7 @@
|
|
|
206
221
|
|
|
207
222
|
/*
|
|
208
223
|
* Re-runs whenever `shouldRun` or anything the leading `draw` reads changes
|
|
209
|
-
* (`safeState`, `safeSize`, `density`, `dotScale`, `gravityOptions`,
|
|
224
|
+
* (`safeState`, `safeSize`, `density`, `dotScale`, `gravityOptions`,
|
|
210
225
|
* `color`, `reducedMotion`, ...) -- Svelte tracks every reactive read inside
|
|
211
226
|
* this body, including transitively through that synchronous `draw` call,
|
|
212
227
|
* so a prop change tears down the previous rAF (the cleanup below) and
|
|
@@ -266,23 +281,18 @@
|
|
|
266
281
|
document.addEventListener('visibilitychange', onVisibilityChange);
|
|
267
282
|
|
|
268
283
|
/*
|
|
269
|
-
*
|
|
270
|
-
*
|
|
271
|
-
*
|
|
272
|
-
*
|
|
273
|
-
*
|
|
284
|
+
* The orb never asks how a host marks its theme -- `theme`, `data-theme`,
|
|
285
|
+
* a class, an inline `style`, `color-scheme`, on `<html>` or `<body>`, or
|
|
286
|
+
* anything else -- it only cares whether the colour it actually resolves
|
|
287
|
+
* to (see `resolveTint`) moved. So this observes every attribute change
|
|
288
|
+
* on both elements, unfiltered, and lets `repaintIfColorChanged` decide
|
|
289
|
+
* whether anything worth a repaint happened.
|
|
274
290
|
*/
|
|
275
|
-
const readTheme = (): void => {
|
|
276
|
-
dark = document.documentElement.getAttribute('data-theme') === 'dark';
|
|
277
|
-
};
|
|
278
|
-
readTheme();
|
|
279
291
|
let themeObserver: MutationObserver | null = null;
|
|
280
292
|
if (typeof MutationObserver !== 'undefined') {
|
|
281
|
-
themeObserver = new MutationObserver(
|
|
282
|
-
themeObserver.observe(document.documentElement, {
|
|
283
|
-
|
|
284
|
-
attributeFilter: ['data-theme']
|
|
285
|
-
});
|
|
293
|
+
themeObserver = new MutationObserver(repaintIfColorChanged);
|
|
294
|
+
themeObserver.observe(document.documentElement, { attributes: true });
|
|
295
|
+
themeObserver.observe(document.body, { attributes: true });
|
|
286
296
|
}
|
|
287
297
|
|
|
288
298
|
const onMotionChange = (event: MediaQueryListEvent): void => {
|
|
@@ -294,24 +304,26 @@
|
|
|
294
304
|
motionQuery.addEventListener('change', onMotionChange);
|
|
295
305
|
}
|
|
296
306
|
|
|
307
|
+
// A host that themes only through `@media (prefers-color-scheme)` changes
|
|
308
|
+
// the inherited colour when the OS flips theme, with no attribute change
|
|
309
|
+
// and no transition for the checks around it to catch.
|
|
310
|
+
let colorSchemeQuery: MediaQueryList | null = null;
|
|
311
|
+
if (typeof window.matchMedia === 'function') {
|
|
312
|
+
colorSchemeQuery = window.matchMedia('(prefers-color-scheme: dark)');
|
|
313
|
+
colorSchemeQuery.addEventListener('change', repaintIfColorChanged);
|
|
314
|
+
}
|
|
315
|
+
|
|
297
316
|
/*
|
|
298
|
-
* A
|
|
299
|
-
*
|
|
300
|
-
*
|
|
301
|
-
*
|
|
302
|
-
* repaint the same frozen instant if the resolved colour actually moved.
|
|
303
|
-
* A running orb re-reads every frame already and needs none of this.
|
|
317
|
+
* A host that transitions its `color` (this repo's own layout fades
|
|
318
|
+
* `body` across a theme switch) leaves a just-frozen frame at the
|
|
319
|
+
* outgoing colour, with nothing else to redraw it: no attribute changed,
|
|
320
|
+
* so the observer above never fires. Re-check once the transition lands.
|
|
304
321
|
*/
|
|
305
322
|
const onColorTransitionEnd = (event: TransitionEvent): void => {
|
|
306
|
-
if (shouldRun || color || canvas === null) {
|
|
307
|
-
return;
|
|
308
|
-
}
|
|
309
323
|
if (event.propertyName !== 'color' && event.propertyName !== '--sui-thinking-orb-color') {
|
|
310
324
|
return;
|
|
311
325
|
}
|
|
312
|
-
|
|
313
|
-
draw(heldInstant());
|
|
314
|
-
}
|
|
326
|
+
repaintIfColorChanged();
|
|
315
327
|
};
|
|
316
328
|
document.addEventListener('transitionend', onColorTransitionEnd);
|
|
317
329
|
|
|
@@ -321,6 +333,7 @@
|
|
|
321
333
|
document.removeEventListener('transitionend', onColorTransitionEnd);
|
|
322
334
|
themeObserver?.disconnect();
|
|
323
335
|
motionQuery?.removeEventListener('change', onMotionChange);
|
|
336
|
+
colorSchemeQuery?.removeEventListener('change', repaintIfColorChanged);
|
|
324
337
|
};
|
|
325
338
|
});
|
|
326
339
|
</script>
|
|
@@ -16,8 +16,11 @@ const TWO_PI = Math.PI * 2;
|
|
|
16
16
|
/** The shared "reads as a form inside a square" contract: radius as a share of `size`. */
|
|
17
17
|
const FORM_RADIUS_RATIO = 0.4;
|
|
18
18
|
const clamp01 = (value) => Math.max(0, Math.min(1, value));
|
|
19
|
+
/** How far toward transparent the farthest dot's ink goes. `paintFrame` multiplies (1 - ink) with
|
|
20
|
+
* `alpha`, so ink reaching 1 would erase the far side of a ring or ribbon however high its alpha. */
|
|
21
|
+
const FAR_INK = 0.6;
|
|
19
22
|
/** Nearer dots read as more saturated tint; `paintFrame` turns low ink into more of `tint`. */
|
|
20
|
-
const depthToInk = (depth) => clamp01(1 - depth);
|
|
23
|
+
const depthToInk = (depth) => clamp01((1 - depth) * FAR_INK);
|
|
21
24
|
/** Farther dots stay at partial opacity rather than fading to nothing, so no instant reads blank. */
|
|
22
25
|
const depthToAlpha = (depth) => clamp01(0.5 + depth * 0.5);
|
|
23
26
|
/** Nearer dots draw a touch larger, reinforcing the depth `paintFrame`'s draw order already implies. */
|
|
@@ -40,10 +43,13 @@ const place = (point, spinAngle, tiltAngle, originPx, worldRadius, baseRadius, s
|
|
|
40
43
|
};
|
|
41
44
|
const EMPTY_STROKES = [];
|
|
42
45
|
// --- composing ---------------------------------------------------------
|
|
43
|
-
|
|
46
|
+
/** Dots along each thread at 64px; `countAlongPath` keeps their spacing as the canvas shrinks. */
|
|
47
|
+
const RIBBON_PER_THREAD_BASE = 36;
|
|
44
48
|
const RIBBON_BASE_DOT_RADIUS = 2.2;
|
|
45
|
-
|
|
46
|
-
|
|
49
|
+
/** Fewer, narrower threads than a full band: at 7 threads across 0.4 rad the 64px ribbon covered
|
|
50
|
+
* most of the sphere and read as a filled ball rather than a strip of cloth. */
|
|
51
|
+
const RIBBON_THREADS = { 64: 5, 32: 4, 20: 3 };
|
|
52
|
+
const RIBBON_HALF_WIDTH = 0.3;
|
|
47
53
|
/** The ribbon's own great circle sits tilted off the spin axis by this much,
|
|
48
54
|
* so spinning genuinely sweeps its width through the frame -- a band that
|
|
49
55
|
* happened to lie flat on the equator would look identical at every spin
|
|
@@ -51,7 +57,9 @@ const RIBBON_HALF_WIDTH = 0.4;
|
|
|
51
57
|
const RIBBON_AXIS_TILT = 0.68;
|
|
52
58
|
const RIBBON_RIPPLE_WAVES = 3;
|
|
53
59
|
const RIBBON_RIPPLE_SPEED = 1.15;
|
|
54
|
-
|
|
60
|
+
/** Kept under RIBBON_HALF_WIDTH: a ripple wider than the band itself swings the ribbon toward
|
|
61
|
+
* the pole and folds it over itself, which reads as a knot rather than cloth. */
|
|
62
|
+
const RIBBON_RIPPLE_AMPLITUDE = 0.18;
|
|
55
63
|
const RIBBON_THREAD_JITTER = 0.1;
|
|
56
64
|
const RIBBON_SPIN_SPEED = 0.48;
|
|
57
65
|
const RIBBON_CAMERA_TILT = 0.45;
|
|
@@ -70,7 +78,7 @@ export const composing = (t, ctx) => {
|
|
|
70
78
|
const worldRadius = ctx.size * FORM_RADIUS_RATIO;
|
|
71
79
|
const originPx = ctx.size / 2;
|
|
72
80
|
const threads = RIBBON_THREADS[ctx.size];
|
|
73
|
-
const perThread =
|
|
81
|
+
const perThread = sizing.countAlongPath(RIBBON_PER_THREAD_BASE);
|
|
74
82
|
const total = threads * perThread;
|
|
75
83
|
const dots = [];
|
|
76
84
|
for (let index = 0; index < total; index += 1) {
|
|
@@ -102,7 +110,9 @@ export const composing = (t, ctx) => {
|
|
|
102
110
|
return { dots, strokes: EMPTY_STROKES };
|
|
103
111
|
};
|
|
104
112
|
// --- breathing -----------------------------------------------------------
|
|
105
|
-
|
|
113
|
+
/** Dots around the ring at 64px. A ring's length grows with `size`, not its area, so this goes
|
|
114
|
+
* through `countAlongPath`: 210 area-scaled dots sat 0.65px apart at 64px and fused into a line. */
|
|
115
|
+
const BREATHING_BASE_COUNT = 32;
|
|
106
116
|
const BREATHING_BASE_DOT_RADIUS = 1.7;
|
|
107
117
|
/** Sits below composing/shaping's ~0.4: at the peak of its breath this ring
|
|
108
118
|
* already swells by its amplitude plus its shape wobble below, so a resting
|
|
@@ -125,7 +135,7 @@ export const breathing = (t, ctx) => {
|
|
|
125
135
|
const sizing = modeSizing(ctx.size, ctx.density, ctx.dotScale);
|
|
126
136
|
const worldRadius = ctx.size * BREATHING_WORLD_RADIUS_RATIO;
|
|
127
137
|
const originPx = ctx.size / 2;
|
|
128
|
-
const count = sizing.
|
|
138
|
+
const count = sizing.countAlongPath(BREATHING_BASE_COUNT);
|
|
129
139
|
const breathe = Math.sin(t * BREATHING_SPEED);
|
|
130
140
|
const dots = [];
|
|
131
141
|
for (let index = 0; index < count; index += 1) {
|
|
@@ -144,7 +154,8 @@ export const breathing = (t, ctx) => {
|
|
|
144
154
|
return { dots, strokes: EMPTY_STROKES };
|
|
145
155
|
};
|
|
146
156
|
// --- shaping ---------------------------------------------------------------
|
|
147
|
-
|
|
157
|
+
/** Dots around the outline at 64px, through `countAlongPath` for the same reason as breathing. */
|
|
158
|
+
const SHAPING_BASE_COUNT = 36;
|
|
148
159
|
const SHAPING_BASE_DOT_RADIUS = 1.7;
|
|
149
160
|
const SHAPING_CYCLE_SECONDS = 12;
|
|
150
161
|
// One full turn per morph cycle, so the shape and its orientation both land
|
|
@@ -169,7 +180,7 @@ export const shaping = (t, ctx) => {
|
|
|
169
180
|
const sizing = modeSizing(ctx.size, ctx.density, ctx.dotScale);
|
|
170
181
|
const worldRadius = ctx.size * FORM_RADIUS_RATIO;
|
|
171
182
|
const originPx = ctx.size / 2;
|
|
172
|
-
const count = sizing.
|
|
183
|
+
const count = sizing.countAlongPath(SHAPING_BASE_COUNT);
|
|
173
184
|
const cyclePos = (((t / SHAPING_CYCLE_SECONDS) % 1) + 1) % 1;
|
|
174
185
|
const phaseFloat = cyclePos * 3;
|
|
175
186
|
const phaseIndex = Math.min(2, Math.floor(phaseFloat));
|
|
@@ -8,5 +8,5 @@
|
|
|
8
8
|
import type { ModeFn } from '../types';
|
|
9
9
|
/** A few nodes on a sphere; lines to near neighbours carry small travelling pulses. */
|
|
10
10
|
export declare const connecting: ModeFn;
|
|
11
|
-
/** Three strands wrapped around a sphere, crossing
|
|
11
|
+
/** Three closed strands wrapped around a sphere, crossing over and under each other as they turn. */
|
|
12
12
|
export declare const weaving: ModeFn;
|
|
@@ -25,11 +25,14 @@ const squaredDistance = (a, b) => {
|
|
|
25
25
|
// connecting -- a few nodes on a sphere, linked to their nearest neighbours,
|
|
26
26
|
// with small bright pulses running along the links.
|
|
27
27
|
// ---------------------------------------------------------------------------
|
|
28
|
-
|
|
28
|
+
/** A few nodes, not a molecule: at 16 nodes x 3 neighbours the 64px graph carried ~24 edges, each
|
|
29
|
+
* with its own pulse, and the pulses were lost among the nodes. */
|
|
30
|
+
const NODE_BASE_COUNT = 10;
|
|
29
31
|
const MIN_NODE_COUNT = 6;
|
|
30
|
-
const NEIGHBOR_COUNT =
|
|
32
|
+
const NEIGHBOR_COUNT = 2;
|
|
31
33
|
const NODE_BASE_RADIUS = 3.4;
|
|
32
|
-
|
|
34
|
+
/** Well under a node's radius, so a pulse reads as something travelling a link, not another node. */
|
|
35
|
+
const PULSE_BASE_RADIUS = 1.4;
|
|
33
36
|
const EDGE_BASE_WIDTH = 1.1;
|
|
34
37
|
const NODE_ROTATE_SPEED = 0.35;
|
|
35
38
|
const NODE_TILT = 0.45;
|
|
@@ -104,63 +107,75 @@ export const connecting = (t, ctx) => {
|
|
|
104
107
|
return { dots: [...nodeDots, ...pulses], strokes };
|
|
105
108
|
};
|
|
106
109
|
// ---------------------------------------------------------------------------
|
|
107
|
-
// weaving -- three strands
|
|
108
|
-
//
|
|
109
|
-
//
|
|
110
|
+
// weaving -- three closed strands wrapped around a sphere like the windings on
|
|
111
|
+
// a ball of yarn; the depth sort in `paintFrame` is what makes them cross over
|
|
112
|
+
// and under each other.
|
|
110
113
|
// ---------------------------------------------------------------------------
|
|
111
114
|
const STRAND_COUNT = 3;
|
|
112
|
-
|
|
113
|
-
const
|
|
114
|
-
/**
|
|
115
|
-
*
|
|
116
|
-
|
|
117
|
-
|
|
115
|
+
/** Points around each closed strand at 64px, through `countAlongPath`. */
|
|
116
|
+
const STRAND_POINTS_BASE_COUNT = 40;
|
|
117
|
+
/** Enough points that a strand still draws as a curve at 20px; at 10 its segments were long
|
|
118
|
+
* enough to show as straight edges and the three strands drew an angular cage. */
|
|
119
|
+
const MIN_STRAND_POINTS = 16;
|
|
120
|
+
/** Each strand is a great circle tilted this far off the horizontal, and the three are turned
|
|
121
|
+
* 120 degrees apart about the vertical axis, so every pair crosses twice per turn. A pole-to-pole
|
|
122
|
+
* spiral kept projecting two strands onto nearly the same path. */
|
|
123
|
+
const STRAND_INCLINATION = 0.6;
|
|
124
|
+
/** A slow wave running along each strand, so the three read as threads being worked rather than
|
|
125
|
+
* three rigid hoops. Small, so the wave never folds a strand across its neighbour's path. */
|
|
126
|
+
const STRAND_WAVE_COUNT = 3;
|
|
127
|
+
const STRAND_WAVE_AMPLITUDE = 0.12;
|
|
128
|
+
const STRAND_WAVE_SPEED = 0.9;
|
|
118
129
|
const STRAND_ROTATE_SPEED = 0.3;
|
|
119
|
-
|
|
130
|
+
/** How far the camera looks down on the sphere: 1.1 rad, about 63 degrees. A ring turns edge-on,
|
|
131
|
+
* and draws as a straight bar, when its axis is square to the line of sight. Each ring's axis sits
|
|
132
|
+
* STRAND_INCLINATION (about 34 degrees) off vertical, and this tilt leaves the vertical about
|
|
133
|
+
* 90 - 63 = 27 degrees off the line of sight, so a ring's axis is never more than 34 + 27 = 61
|
|
134
|
+
* degrees off it. No spin angle, and so no paused frame, draws a ring flatter than about
|
|
135
|
+
* cos 61 = 48% of its width. */
|
|
136
|
+
const STRAND_TILT = 1.1;
|
|
120
137
|
const STRAND_DOT_BASE_RADIUS = 1.6;
|
|
121
138
|
const STRAND_STROKE_BASE_WIDTH = 1.4;
|
|
122
|
-
/**
|
|
123
|
-
*
|
|
124
|
-
|
|
125
|
-
const
|
|
126
|
-
/**
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
* this sits comfortably past that so every pair of strands crosses, not just
|
|
131
|
-
* wobbles toward each other. */
|
|
132
|
-
const STRAND_BRAID_SWING = 1.3;
|
|
139
|
+
/** At the small sizes the strand lines carry the motif and the beads only clutter it, so lines
|
|
140
|
+
* thicken and beads shrink as the canvas does. */
|
|
141
|
+
const STRAND_STROKE_SIZE_FACTOR = { 64: 1, 32: 1.2, 20: 1.5 };
|
|
142
|
+
const STRAND_DOT_SIZE_FACTOR = { 64: 1, 32: 0.85, 20: 0.7 };
|
|
143
|
+
/** Depth still dims a strand's far side, but only this far, so no stretch of it disappears. */
|
|
144
|
+
const STRAND_DEPTH_INK = 0.45;
|
|
145
|
+
/** A slight per-strand shade; the paths and their over/under crossings are what separate them. */
|
|
146
|
+
const STRAND_SHADE_STEP = 0.1;
|
|
133
147
|
const strandBaseAngle = (strand) => (strand / STRAND_COUNT) * Math.PI * 2;
|
|
134
148
|
/**
|
|
135
|
-
* The `pointIndex`-th of `pointsPerStrand` points
|
|
136
|
-
*
|
|
137
|
-
*
|
|
138
|
-
*
|
|
139
|
-
*
|
|
140
|
-
* which is what keeps every point exactly on the sphere at every instant.
|
|
149
|
+
* The `pointIndex`-th of `pointsPerStrand` points around closed `strand`: a
|
|
150
|
+
* great circle (the first and last points meet) with a small wave in latitude
|
|
151
|
+
* travelling along it, inclined by `STRAND_INCLINATION`, turned to its own
|
|
152
|
+
* 120-degree slot and spun with the rest. Latitude and longitude keep every
|
|
153
|
+
* point exactly on the sphere, whatever the wave does.
|
|
141
154
|
*/
|
|
142
155
|
const strandPoint = (strand, pointIndex, pointsPerStrand, sphereRadius, t) => {
|
|
143
|
-
const u = pointIndex / (pointsPerStrand - 1);
|
|
144
|
-
const
|
|
145
|
-
|
|
146
|
-
const
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
156
|
+
const u = (pointIndex / (pointsPerStrand - 1)) * Math.PI * 2;
|
|
157
|
+
const latitude = STRAND_WAVE_AMPLITUDE *
|
|
158
|
+
Math.sin(u * STRAND_WAVE_COUNT + t * STRAND_WAVE_SPEED + strandBaseAngle(strand));
|
|
159
|
+
const onCircle = {
|
|
160
|
+
x: sphereRadius * Math.cos(latitude) * Math.cos(u),
|
|
161
|
+
y: sphereRadius * Math.sin(latitude),
|
|
162
|
+
z: sphereRadius * Math.cos(latitude) * Math.sin(u)
|
|
163
|
+
};
|
|
164
|
+
const inclined = rotateX(onCircle, STRAND_INCLINATION);
|
|
165
|
+
const turned = rotateY(inclined, strandBaseAngle(strand) + t * STRAND_ROTATE_SPEED);
|
|
166
|
+
return rotateX(turned, STRAND_TILT);
|
|
152
167
|
};
|
|
153
|
-
/** Three strands wrapped around a sphere, crossing
|
|
168
|
+
/** Three closed strands wrapped around a sphere, crossing over and under each other as they turn. */
|
|
154
169
|
export const weaving = (t, ctx) => {
|
|
155
170
|
const { sizing, originPx, sphereRadius } = sphereGeometry(ctx);
|
|
156
|
-
const pointsPerStrand = Math.max(MIN_STRAND_POINTS, sizing.
|
|
171
|
+
const pointsPerStrand = Math.max(MIN_STRAND_POINTS, sizing.countAlongPath(STRAND_POINTS_BASE_COUNT));
|
|
157
172
|
const strands = Array.from({ length: STRAND_COUNT }, (_, strand) => Array.from({ length: pointsPerStrand }, (_, pointIndex) => project(strandPoint(strand, pointIndex, pointsPerStrand, sphereRadius, t), originPx, sphereRadius)));
|
|
158
173
|
const dots = strands.flatMap((points, strand) => points.map((p) => ({
|
|
159
174
|
x: p.x,
|
|
160
175
|
y: p.y,
|
|
161
176
|
depth: p.depth,
|
|
162
|
-
radius: sizing.radius(STRAND_DOT_BASE_RADIUS),
|
|
163
|
-
ink: clamp01(1 - p.depth *
|
|
177
|
+
radius: sizing.radius(STRAND_DOT_BASE_RADIUS) * STRAND_DOT_SIZE_FACTOR[ctx.size],
|
|
178
|
+
ink: clamp01((1 - p.depth) * STRAND_DEPTH_INK + strand * STRAND_SHADE_STEP),
|
|
164
179
|
alpha: 0.55 + p.depth * 0.4
|
|
165
180
|
})));
|
|
166
181
|
const strokes = strands.flatMap((points, strand) => points.slice(1).map((p, i) => {
|
|
@@ -172,8 +187,8 @@ export const weaving = (t, ctx) => {
|
|
|
172
187
|
x2: p.x,
|
|
173
188
|
y2: p.y,
|
|
174
189
|
depth,
|
|
175
|
-
width: sizing.radius(STRAND_STROKE_BASE_WIDTH),
|
|
176
|
-
ink: clamp01(1 - depth *
|
|
190
|
+
width: sizing.radius(STRAND_STROKE_BASE_WIDTH) * STRAND_STROKE_SIZE_FACTOR[ctx.size],
|
|
191
|
+
ink: clamp01((1 - depth) * STRAND_DEPTH_INK + strand * STRAND_SHADE_STEP),
|
|
177
192
|
alpha: 0.6 + depth * 0.35
|
|
178
193
|
};
|
|
179
194
|
}));
|
|
@@ -46,21 +46,17 @@ const toStroke = (from, to, width, ink, alpha) => ({
|
|
|
46
46
|
* as noise once density thins the count out at 32/20px, while a handful of
|
|
47
47
|
* particles held close together always reads as motion along a path. */
|
|
48
48
|
const WORKING_TRAIN_BASE_COUNT = 22;
|
|
49
|
-
/** Keeps at least this many short arcs on screen at
|
|
50
|
-
* area scaler alone already clears
|
|
51
|
-
|
|
52
|
-
* shading fades whichever half of each orbit is on the far side of the
|
|
53
|
-
* sphere at a given instant almost to the background -- one train per orbit
|
|
54
|
-
* left whole quadrants with no train currently on the near side to fill
|
|
55
|
-
* them; two independently-phased laps around the six orbits keeps at least
|
|
56
|
-
* a couple of quadrants covered at every instant, not just on average. */
|
|
57
|
-
const WORKING_MIN_TRAINS = { 64: 3, 32: 3, 20: 12 };
|
|
49
|
+
/** Keeps at least this many short arcs on screen at 64px (32/20px use WORKING_SMALL_LAYOUT). The
|
|
50
|
+
* area scaler alone already clears it at the default density; it only bites when density is low. */
|
|
51
|
+
const WORKING_MIN_TRAINS_64 = 3;
|
|
58
52
|
const WORKING_TRAIN_LENGTH = 5;
|
|
59
53
|
/** How far apart, in radians, a train's particles trail behind its lead --
|
|
60
54
|
* wide enough to read as a short curved arc, short enough to stay a cluster
|
|
61
55
|
* rather than smearing back into the full-orbit scatter this replaces. */
|
|
62
56
|
const WORKING_TRAIN_ARC_SPAN = 0.5;
|
|
63
|
-
|
|
57
|
+
/** At 1.6, with a +/-25% jitter, 20px dots came out 0.6-1px across and the arcs blurred into a
|
|
58
|
+
* smudge; this and the narrower jitter below keep a train a visible stroke at every size. */
|
|
59
|
+
const WORKING_BASE_RADIUS_PX = 2.2;
|
|
64
60
|
const WORKING_ORBIT_COUNT = 6;
|
|
65
61
|
const WORKING_ANGULAR_SPEED = 1.1;
|
|
66
62
|
/** How far an orbit's `weight` can push its dots' ink away from the shared
|
|
@@ -83,19 +79,58 @@ const workingOrbit = (orbit) => {
|
|
|
83
79
|
weight: 0.35 + 0.65 * hashUnit(seed + 15)
|
|
84
80
|
};
|
|
85
81
|
};
|
|
82
|
+
/** At 32/20px six randomly tilted orbits of short arcs collapse into one busy cluster: each arc is
|
|
83
|
+
* only a few px long and the orbits overlap. These sizes instead spread a few orbits evenly around
|
|
84
|
+
* the view axis (like an atom symbol) and give each train a long arc, so every train draws a
|
|
85
|
+
* visible curve and the separate orbits stay readable. */
|
|
86
|
+
const WORKING_SMALL_LAYOUT = {
|
|
87
|
+
32: { orbits: 4, trainLength: 6, arcSpan: 1 },
|
|
88
|
+
20: { orbits: 3, trainLength: 7, arcSpan: 1.25 }
|
|
89
|
+
};
|
|
90
|
+
/** How far each small-size orbit tips out of edge-on. Its projection is an ellipse sin(tilt) as
|
|
91
|
+
* tall as it is wide; near 1 rad every orbit projects to nearly the same circle and rolling it
|
|
92
|
+
* about the view axis changes nothing, so the orbits merged into one ring. */
|
|
93
|
+
const WORKING_SMALL_ORBIT_TILT = 0.5;
|
|
94
|
+
/** At 32/20px each orbit's path is drawn as a faint thin ellipse under its trains: a 20px train
|
|
95
|
+
* alone is too short to show which ellipse it is travelling, so without the path the trains read
|
|
96
|
+
* as a pinwheel rather than as particles circling several tilted orbits. */
|
|
97
|
+
const WORKING_PATH_SEGMENTS = 24;
|
|
98
|
+
const WORKING_PATH_WIDTH_PX = 0.8;
|
|
99
|
+
const WORKING_PATH_INK = 0.5;
|
|
100
|
+
const WORKING_PATH_ALPHA = 0.45;
|
|
101
|
+
const WORKING_SMALL_ORBIT_RADIUS = 0.85;
|
|
102
|
+
const WORKING_SMALL_SPEEDS = [0.8, 1.15, 1.45, 1];
|
|
103
|
+
/** One orbit of the small-size layout: shared tilt, rolled evenly around the view axis. */
|
|
104
|
+
const workingSmallOrbit = (orbit, orbits) => ({
|
|
105
|
+
...workingOrbit(orbit),
|
|
106
|
+
tilt: WORKING_SMALL_ORBIT_TILT,
|
|
107
|
+
roll: (orbit / orbits) * Math.PI,
|
|
108
|
+
orbitRadiusFactor: WORKING_SMALL_ORBIT_RADIUS,
|
|
109
|
+
speedFactor: WORKING_SMALL_SPEEDS[orbit % WORKING_SMALL_SPEEDS.length]
|
|
110
|
+
});
|
|
86
111
|
export const working = (t, ctx) => {
|
|
87
112
|
const sizing = modeSizing(ctx.size, ctx.density, ctx.dotScale);
|
|
88
113
|
const origin = originOf(ctx);
|
|
89
114
|
const worldRadius = worldRadiusOf(ctx);
|
|
90
|
-
const
|
|
91
|
-
|
|
115
|
+
const small = WORKING_SMALL_LAYOUT[ctx.size];
|
|
116
|
+
// Small sizes run two opposite trains per orbit (scaled by density); 64px keeps its own swarm.
|
|
117
|
+
const lapsPerOrbit = Math.max(1, Math.round(2 * ctx.density));
|
|
118
|
+
const trainCount = small
|
|
119
|
+
? small.orbits * lapsPerOrbit
|
|
120
|
+
: Math.max(WORKING_MIN_TRAINS_64, sizing.count(WORKING_TRAIN_BASE_COUNT));
|
|
121
|
+
const trainLength = small ? small.trainLength : WORKING_TRAIN_LENGTH;
|
|
122
|
+
const arcStep = (small ? small.arcSpan : WORKING_TRAIN_ARC_SPAN) / (trainLength - 1);
|
|
92
123
|
const dots = [];
|
|
93
124
|
for (let train = 0; train < trainCount; train += 1) {
|
|
94
|
-
const orbit =
|
|
95
|
-
|
|
125
|
+
const orbit = small
|
|
126
|
+
? workingSmallOrbit(train % small.orbits, small.orbits)
|
|
127
|
+
: workingOrbit(train % WORKING_ORBIT_COUNT);
|
|
128
|
+
const leadPhase = small
|
|
129
|
+
? (Math.floor(train / small.orbits) / lapsPerOrbit) * TWO_PI + (train % small.orbits) * 0.9
|
|
130
|
+
: hashUnit(train * 5 + 1) * TWO_PI;
|
|
96
131
|
const leadAngle = leadPhase + t * WORKING_ANGULAR_SPEED * orbit.speedFactor;
|
|
97
132
|
const orbitRadius = worldRadius * orbit.orbitRadiusFactor;
|
|
98
|
-
for (let slot = 0; slot <
|
|
133
|
+
for (let slot = 0; slot < trainLength; slot += 1) {
|
|
99
134
|
const angle = leadAngle - slot * arcStep;
|
|
100
135
|
const planar = {
|
|
101
136
|
x: Math.cos(angle) * orbitRadius,
|
|
@@ -106,17 +141,35 @@ export const working = (t, ctx) => {
|
|
|
106
141
|
const point = rotateZ(tilted, orbit.roll);
|
|
107
142
|
const projected = project(point, origin, worldRadius);
|
|
108
143
|
const seed = train * 13 + slot * 7 + 2;
|
|
109
|
-
const trail = 1 - slot / (
|
|
144
|
+
const trail = 1 - slot / (trainLength - 1);
|
|
110
145
|
const ink = shadeByDepth(projected.depth) +
|
|
111
146
|
(hashUnit(seed) - 0.5) * 0.08 -
|
|
112
147
|
(orbit.weight - 0.5) * WORKING_ORBIT_INK_SPREAD;
|
|
113
148
|
const alpha = (WORKING_TRAIL_ALPHA_FLOOR + (1 - WORKING_TRAIL_ALPHA_FLOOR) * trail) *
|
|
114
149
|
(WORKING_ORBIT_ALPHA_FLOOR + (1 - WORKING_ORBIT_ALPHA_FLOOR) * orbit.weight);
|
|
115
|
-
const radius = sizing.radius(WORKING_BASE_RADIUS_PX) * (0.
|
|
150
|
+
const radius = sizing.radius(WORKING_BASE_RADIUS_PX) * (0.9 + 0.25 * hashUnit(seed + 3));
|
|
116
151
|
dots.push(toDot(projected, radius, ink, alpha));
|
|
117
152
|
}
|
|
118
153
|
}
|
|
119
|
-
|
|
154
|
+
const paths = small
|
|
155
|
+
? Array.from({ length: small.orbits }, (_unused, orbitIndex) => {
|
|
156
|
+
const orbit = workingSmallOrbit(orbitIndex, small.orbits);
|
|
157
|
+
const orbitRadius = worldRadius * orbit.orbitRadiusFactor;
|
|
158
|
+
const points = Array.from({ length: WORKING_PATH_SEGMENTS + 1 }, (_unusedPoint, j) => {
|
|
159
|
+
const angle = (j / WORKING_PATH_SEGMENTS) * TWO_PI;
|
|
160
|
+
const planar = {
|
|
161
|
+
x: Math.cos(angle) * orbitRadius,
|
|
162
|
+
y: 0,
|
|
163
|
+
z: Math.sin(angle) * orbitRadius
|
|
164
|
+
};
|
|
165
|
+
return project(rotateZ(rotateX(planar, orbit.tilt), orbit.roll), origin, worldRadius);
|
|
166
|
+
});
|
|
167
|
+
return points
|
|
168
|
+
.slice(1)
|
|
169
|
+
.map((to, j) => toStroke(points[j], to, sizing.radius(WORKING_PATH_WIDTH_PX), WORKING_PATH_INK, WORKING_PATH_ALPHA));
|
|
170
|
+
}).flat()
|
|
171
|
+
: [];
|
|
172
|
+
return { dots, strokes: paths };
|
|
120
173
|
};
|
|
121
174
|
// ---------------------------------------------------------------------------
|
|
122
175
|
// searching -- a dotted globe with a meridian band sweeping around it
|
|
@@ -200,9 +253,23 @@ const SOLVING_TILT = -0.5;
|
|
|
200
253
|
* cluster relative to its neighbours instead of only reshuffling texture
|
|
201
254
|
* that looks the same before and after. */
|
|
202
255
|
const SOLVING_LANDMARKS_PER_TIER = 3;
|
|
256
|
+
/** One phase for every tier, so in the solved pose each tier's landmarks line up into the same
|
|
257
|
+
* three columns and a turned tier visibly breaks out of them. A per-tier phase scattered them
|
|
258
|
+
* even when solved, leaving nothing for a turn to disturb. */
|
|
259
|
+
const SOLVING_LANDMARK_PHASE = hashUnit(5) * TWO_PI;
|
|
203
260
|
const SOLVING_LANDMARK_RADIUS_PX = 3.1;
|
|
204
261
|
const SOLVING_LANDMARK_INK_BOOST = 0.45;
|
|
205
262
|
const SOLVING_LANDMARK_ALPHA = 0.9;
|
|
263
|
+
/** Each landmark also draws a short meridian stroke spanning its tier. Solved, the strokes of all
|
|
264
|
+
* tiers join into three unbroken vertical lines; a turned tier's strokes jump sideways and break
|
|
265
|
+
* the lines into a visible staircase. Held scrambled, loose landmark dots alone still formed tidy
|
|
266
|
+
* columns of their own and read as just another solved pose. */
|
|
267
|
+
const SOLVING_MERIDIAN_POINTS_PER_TIER = 3;
|
|
268
|
+
const SOLVING_MERIDIAN_WIDTH_PX = 1.6;
|
|
269
|
+
const SOLVING_MERIDIAN_INK_BOOST = 0.35;
|
|
270
|
+
const SOLVING_MERIDIAN_ALPHA = 0.85;
|
|
271
|
+
/** The meridians stop this far short of the poles, where all three would otherwise converge. */
|
|
272
|
+
const SOLVING_MERIDIAN_Y_LIMIT = 0.9;
|
|
206
273
|
/** A static ring of short strokes at each cut between tiers, unaffected by
|
|
207
274
|
* any turn, so the "cut into bands" structure reads even while the puzzle
|
|
208
275
|
* sits solved and nothing is moving. */
|
|
@@ -270,8 +337,7 @@ export const solving = (t, ctx) => {
|
|
|
270
337
|
const yUnit = solvingTierCenterYUnit(tier);
|
|
271
338
|
const y = yUnit * worldRadius;
|
|
272
339
|
const ringRadius = Math.sqrt(Math.max(0, 1 - yUnit * yUnit)) * worldRadius;
|
|
273
|
-
const
|
|
274
|
-
const longitude = phase + (slot / SOLVING_LANDMARKS_PER_TIER) * TWO_PI;
|
|
340
|
+
const longitude = SOLVING_LANDMARK_PHASE + (slot / SOLVING_LANDMARKS_PER_TIER) * TWO_PI;
|
|
275
341
|
const base = {
|
|
276
342
|
x: Math.cos(longitude) * ringRadius,
|
|
277
343
|
y,
|
|
@@ -299,7 +365,31 @@ export const solving = (t, ctx) => {
|
|
|
299
365
|
});
|
|
300
366
|
return Array.from({ length: SOLVING_SEAM_SEGMENTS }, (_unusedSegment, j) => toStroke(ringPoints[j], ringPoints[j + 1], seamWidth, SOLVING_SEAM_INK, SOLVING_SEAM_ALPHA));
|
|
301
367
|
}).flat();
|
|
302
|
-
|
|
368
|
+
const meridianWidth = sizing.radius(SOLVING_MERIDIAN_WIDTH_PX);
|
|
369
|
+
const meridians = Array.from({ length: SOLVING_TIER_COUNT * SOLVING_LANDMARKS_PER_TIER }, (_unused, i) => {
|
|
370
|
+
const tier = Math.floor(i / SOLVING_LANDMARKS_PER_TIER);
|
|
371
|
+
const slot = i % SOLVING_LANDMARKS_PER_TIER;
|
|
372
|
+
const longitude = SOLVING_LANDMARK_PHASE + (slot / SOLVING_LANDMARKS_PER_TIER) * TWO_PI;
|
|
373
|
+
const topYUnit = Math.min(SOLVING_MERIDIAN_Y_LIMIT, 1 - (2 * tier) / SOLVING_TIER_COUNT);
|
|
374
|
+
const bottomYUnit = Math.max(-SOLVING_MERIDIAN_Y_LIMIT, 1 - (2 * (tier + 1)) / SOLVING_TIER_COUNT);
|
|
375
|
+
const points = Array.from({ length: SOLVING_MERIDIAN_POINTS_PER_TIER }, (_unusedPoint, j) => {
|
|
376
|
+
const yUnit = topYUnit + ((bottomYUnit - topYUnit) * j) / (SOLVING_MERIDIAN_POINTS_PER_TIER - 1);
|
|
377
|
+
const ringRadius = Math.sqrt(Math.max(0, 1 - yUnit * yUnit)) * worldRadius;
|
|
378
|
+
const base = {
|
|
379
|
+
x: Math.cos(longitude) * ringRadius,
|
|
380
|
+
y: yUnit * worldRadius,
|
|
381
|
+
z: Math.sin(longitude) * ringRadius
|
|
382
|
+
};
|
|
383
|
+
const turned = rotateY(base, solvingTurnAngle(tier, cyclePos));
|
|
384
|
+
return project(rotateX(turned, SOLVING_TILT), origin, worldRadius);
|
|
385
|
+
});
|
|
386
|
+
return points.slice(1).map((to, j) => {
|
|
387
|
+
const from = points[j];
|
|
388
|
+
const depth = (from.depth + to.depth) / 2;
|
|
389
|
+
return toStroke(from, to, meridianWidth, shadeByDepth(depth) - SOLVING_MERIDIAN_INK_BOOST, SOLVING_MERIDIAN_ALPHA);
|
|
390
|
+
});
|
|
391
|
+
}).flat();
|
|
392
|
+
return { dots: [...texture, ...landmarks], strokes: [...seams, ...meridians] };
|
|
303
393
|
};
|
|
304
394
|
// ---------------------------------------------------------------------------
|
|
305
395
|
// listening -- stacked horizontal rings with a wave rolling through them
|
|
@@ -307,13 +397,17 @@ export const solving = (t, ctx) => {
|
|
|
307
397
|
/** Fewer, fatter rings at the smaller presets read as distinct stacked bands;
|
|
308
398
|
* six thin rings at 20px used to compress into a single smudge. */
|
|
309
399
|
const LISTENING_RING_COUNT = { 64: 5, 32: 4, 20: 3 };
|
|
400
|
+
/** Dots per ring at 64px, through `countAlongPath` so 32px keeps a denser ring than 20px
|
|
401
|
+
* instead of both falling to the minimum below. */
|
|
310
402
|
const LISTENING_DOTS_PER_RING_BASE = 26;
|
|
311
403
|
/** A ring below this many dots reads as a loose cluster of points rather than
|
|
312
404
|
* a line, especially once it is a small ellipse at 20px. */
|
|
313
405
|
const LISTENING_MIN_DOTS_PER_RING = 10;
|
|
314
406
|
const LISTENING_BASE_RADIUS_PX = 1.5;
|
|
315
407
|
const LISTENING_WAVE_SPEED = 0.6;
|
|
316
|
-
|
|
408
|
+
/** How much a ring's dots grow as the wave crests through it. At 0.55 the crest ate most of the
|
|
409
|
+
* gap between rings at 32/20px, where the rings sit only a few px apart. */
|
|
410
|
+
const LISTENING_SWELL = 0.3;
|
|
317
411
|
const LISTENING_LIFT_INK = 0.45;
|
|
318
412
|
const LISTENING_SPIN_SPEED = 0.12;
|
|
319
413
|
/** A ring's own vertical thickness once tilted is (its radius) x sin(tilt); a
|
|
@@ -322,10 +416,10 @@ const LISTENING_SPIN_SPEED = 0.12;
|
|
|
322
416
|
* neighbouring rings' ellipses swallow the empty space between them. Kept
|
|
323
417
|
* shallow rather than flattened to zero so a ring still reads as an ellipse
|
|
324
418
|
* seen slightly from above, not a flat line. */
|
|
325
|
-
const LISTENING_TILT = -0.
|
|
419
|
+
const LISTENING_TILT = -0.1;
|
|
326
420
|
/** Rings are stacked between +/- this fraction of the world radius, short of
|
|
327
421
|
* the poles so the top and bottom rings stay full circles, not points. */
|
|
328
|
-
const LISTENING_Y_SPAN = 0.
|
|
422
|
+
const LISTENING_Y_SPAN = 0.86;
|
|
329
423
|
const listeningRing = (ring, ringCount, worldRadius) => {
|
|
330
424
|
const yUnit = (-1 + (2 * ring + 1) / ringCount) * LISTENING_Y_SPAN;
|
|
331
425
|
const y = yUnit * worldRadius;
|
|
@@ -339,8 +433,7 @@ export const listening = (t, ctx) => {
|
|
|
339
433
|
const origin = originOf(ctx);
|
|
340
434
|
const worldRadius = worldRadiusOf(ctx);
|
|
341
435
|
const ringCount = LISTENING_RING_COUNT[ctx.size];
|
|
342
|
-
const
|
|
343
|
-
const dotsPerRing = Math.max(LISTENING_MIN_DOTS_PER_RING, Math.round(sizing.count(totalBase) / ringCount));
|
|
436
|
+
const dotsPerRing = Math.max(LISTENING_MIN_DOTS_PER_RING, sizing.countAlongPath(LISTENING_DOTS_PER_RING_BASE));
|
|
344
437
|
const dots = Array.from({ length: ringCount }, (_unused, r) => {
|
|
345
438
|
const ring = listeningRing(r, ringCount, worldRadius);
|
|
346
439
|
const wave = ring.wave(t);
|
|
@@ -1,22 +1,27 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Turns one `Frame` into canvas calls. The only place that knows about
|
|
3
|
-
*
|
|
4
|
-
*
|
|
2
|
+
* Turns one `Frame` into canvas calls. The only place that knows about
|
|
3
|
+
* colour -- a mode never sees `tint`, only the 0..1 `ink` it assigns each
|
|
4
|
+
* mark.
|
|
5
5
|
*/
|
|
6
6
|
import type { Rgb } from '../../types';
|
|
7
7
|
import type { Frame } from './types';
|
|
8
|
-
/** What `paintFrame` needs beyond the frame itself: the
|
|
8
|
+
/** What `paintFrame` needs beyond the frame itself: the base colour. */
|
|
9
9
|
export type PaintOptions = {
|
|
10
|
-
dark: boolean;
|
|
11
10
|
tint: Rgb;
|
|
12
11
|
};
|
|
13
12
|
/**
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
13
|
+
* Every mark draws in the tint colour itself -- an exact, testable colour
|
|
14
|
+
* string that never changes with depth. Depth is expressed as transparency
|
|
15
|
+
* instead (see `inkAlpha`), so a mark reads correctly against any
|
|
16
|
+
* background rather than only a solid white or black one.
|
|
18
17
|
*/
|
|
19
|
-
export declare const inkColor: (tint: Rgb
|
|
18
|
+
export declare const inkColor: (tint: Rgb) => string;
|
|
19
|
+
/**
|
|
20
|
+
* Maps `ink` (0 = fully opaque) to the opacity a mark paints at: it fades
|
|
21
|
+
* toward fully transparent as `ink` rises, multiplied with the mark's own
|
|
22
|
+
* `alpha` so the two fades compound rather than override each other.
|
|
23
|
+
*/
|
|
24
|
+
export declare const inkAlpha: (ink: number, alpha: number) => number;
|
|
20
25
|
/**
|
|
21
26
|
* Clears the canvas and draws a `Frame`: every stroke, then every dot, each
|
|
22
27
|
* group sorted far-to-near by `depth` so nearer marks are painted last and
|
|
@@ -1,23 +1,22 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Turns one `Frame` into canvas calls. The only place that knows about
|
|
3
|
-
*
|
|
4
|
-
*
|
|
2
|
+
* Turns one `Frame` into canvas calls. The only place that knows about
|
|
3
|
+
* colour -- a mode never sees `tint`, only the 0..1 `ink` it assigns each
|
|
4
|
+
* mark.
|
|
5
5
|
*/
|
|
6
6
|
const clamp01 = (value) => Math.max(0, Math.min(1, value));
|
|
7
7
|
/**
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
8
|
+
* Every mark draws in the tint colour itself -- an exact, testable colour
|
|
9
|
+
* string that never changes with depth. Depth is expressed as transparency
|
|
10
|
+
* instead (see `inkAlpha`), so a mark reads correctly against any
|
|
11
|
+
* background rather than only a solid white or black one.
|
|
12
12
|
*/
|
|
13
|
-
export const inkColor = (tint
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
};
|
|
13
|
+
export const inkColor = (tint) => `rgb(${tint.r} ${tint.g} ${tint.b})`;
|
|
14
|
+
/**
|
|
15
|
+
* Maps `ink` (0 = fully opaque) to the opacity a mark paints at: it fades
|
|
16
|
+
* toward fully transparent as `ink` rises, multiplied with the mark's own
|
|
17
|
+
* `alpha` so the two fades compound rather than override each other.
|
|
18
|
+
*/
|
|
19
|
+
export const inkAlpha = (ink, alpha) => clamp01(1 - clamp01(ink)) * clamp01(alpha);
|
|
21
20
|
/**
|
|
22
21
|
* Clears the canvas and draws a `Frame`: every stroke, then every dot, each
|
|
23
22
|
* group sorted far-to-near by `depth` so nearer marks are painted last and
|
|
@@ -25,10 +24,11 @@ export const inkColor = (tint, ink, dark) => {
|
|
|
25
24
|
*/
|
|
26
25
|
export const paintFrame = (ctx, frame, options) => {
|
|
27
26
|
ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
|
|
27
|
+
const color = inkColor(options.tint);
|
|
28
28
|
const strokes = [...frame.strokes].sort((a, b) => a.depth - b.depth);
|
|
29
29
|
for (const stroke of strokes) {
|
|
30
|
-
ctx.strokeStyle =
|
|
31
|
-
ctx.globalAlpha =
|
|
30
|
+
ctx.strokeStyle = color;
|
|
31
|
+
ctx.globalAlpha = inkAlpha(stroke.ink, stroke.alpha);
|
|
32
32
|
ctx.lineWidth = stroke.width;
|
|
33
33
|
ctx.beginPath();
|
|
34
34
|
ctx.moveTo(stroke.x1, stroke.y1);
|
|
@@ -37,8 +37,8 @@ export const paintFrame = (ctx, frame, options) => {
|
|
|
37
37
|
}
|
|
38
38
|
const dots = [...frame.dots].sort((a, b) => a.depth - b.depth);
|
|
39
39
|
for (const dot of dots) {
|
|
40
|
-
ctx.fillStyle =
|
|
41
|
-
ctx.globalAlpha =
|
|
40
|
+
ctx.fillStyle = color;
|
|
41
|
+
ctx.globalAlpha = inkAlpha(dot.ink, dot.alpha);
|
|
42
42
|
ctx.beginPath();
|
|
43
43
|
ctx.arc(dot.x, dot.y, dot.radius, 0, Math.PI * 2);
|
|
44
44
|
ctx.fill();
|
|
@@ -18,9 +18,13 @@ export type Projected = {
|
|
|
18
18
|
depth: number;
|
|
19
19
|
scale: number;
|
|
20
20
|
};
|
|
21
|
-
/** The
|
|
21
|
+
/** The scalers `modeSizing` hands back: multiply a mode's own base counts and radii by them. */
|
|
22
22
|
export type ModeSizing = {
|
|
23
|
+
/** For marks spread over an area (a swarm, a globe's surface): scales with `size` squared. */
|
|
23
24
|
count: (base: number) => number;
|
|
25
|
+
/** For marks spaced along a line (a ring, a thread): scales with `size`, so the gap between
|
|
26
|
+
* neighbours keeps the same share of the canvas at every size instead of closing up. */
|
|
27
|
+
countAlongPath: (base: number) => number;
|
|
24
28
|
radius: (base: number) => number;
|
|
25
29
|
};
|
|
26
30
|
/** Rotates a point about the X axis (mixes y and z). */
|
|
@@ -57,7 +61,8 @@ export declare const hashUnit: (seed: number) => number;
|
|
|
57
61
|
/**
|
|
58
62
|
* Turns `(size, density, dotScale)` into a count scaler and a radius scaler,
|
|
59
63
|
* so every mode derives its dot counts and radii the same way instead of
|
|
60
|
-
* keeping its own per-size table. Counts scale with area (`size` squared)
|
|
64
|
+
* keeping its own per-size table. Counts scale with area (`size` squared) for
|
|
65
|
+
* marks spread over a surface and with `size` for marks spaced along a path;
|
|
61
66
|
* radii grow sub-linearly, with a floor that keeps dots visible at 20px.
|
|
62
67
|
*/
|
|
63
68
|
export declare const modeSizing: (size: ModeSize, density: number, dotScale: number) => ModeSizing;
|
|
@@ -100,7 +100,8 @@ const MIN_DOT_RADIUS_PX = 0.6;
|
|
|
100
100
|
/**
|
|
101
101
|
* Turns `(size, density, dotScale)` into a count scaler and a radius scaler,
|
|
102
102
|
* so every mode derives its dot counts and radii the same way instead of
|
|
103
|
-
* keeping its own per-size table. Counts scale with area (`size` squared)
|
|
103
|
+
* keeping its own per-size table. Counts scale with area (`size` squared) for
|
|
104
|
+
* marks spread over a surface and with `size` for marks spaced along a path;
|
|
104
105
|
* radii grow sub-linearly, with a floor that keeps dots visible at 20px.
|
|
105
106
|
*/
|
|
106
107
|
export const modeSizing = (size, density, dotScale) => {
|
|
@@ -110,6 +111,7 @@ export const modeSizing = (size, density, dotScale) => {
|
|
|
110
111
|
const safeDotScale = dotScale > 0 ? dotScale : 0.1;
|
|
111
112
|
return {
|
|
112
113
|
count: (base) => Math.max(1, Math.round(base * areaRatio * safeDensity)),
|
|
114
|
+
countAlongPath: (base) => Math.max(1, Math.round(base * sizeRatio * safeDensity)),
|
|
113
115
|
radius: (base) => Math.max(MIN_DOT_RADIUS_PX, base * sizeRatio ** RADIUS_GROWTH_EXPONENT * safeDotScale)
|
|
114
116
|
};
|
|
115
117
|
};
|
package/dist-wc/index.js
CHANGED
|
@@ -24017,6 +24017,7 @@ var clamp01$5 = (e) => Math.max(0, Math.min(1, e)), rotateX = (e, t) => {
|
|
|
24017
24017
|
let i = e / REFERENCE_SIZE, a = i * i, o = t > 0 ? t : .1, s = n > 0 ? n : .1;
|
|
24018
24018
|
return {
|
|
24019
24019
|
count: (e) => Math.max(1, Math.round(e * a * o)),
|
|
24020
|
+
countAlongPath: (e) => Math.max(1, Math.round(e * i * o)),
|
|
24020
24021
|
radius: (e) => Math.max(MIN_DOT_RADIUS_PX, e * i ** RADIUS_GROWTH_EXPONENT * s)
|
|
24021
24022
|
};
|
|
24022
24023
|
}, GRAVITY_DEFAULTS = {
|
|
@@ -24055,15 +24056,12 @@ var clamp01$5 = (e) => Math.max(0, Math.min(1, e)), rotateX = (e, t) => {
|
|
|
24055
24056
|
}, attract = (e, t, n) => t === null ? e : {
|
|
24056
24057
|
dots: e.dots.map((e) => attractDot(e, t, n)),
|
|
24057
24058
|
strokes: e.strokes.map((e) => attractStroke(e, t, n))
|
|
24058
|
-
}, clamp01$3 = (e) => Math.max(0, Math.min(1, e)), inkColor = (e, t, n) => {
|
|
24059
|
-
let i = clamp01$3(t), a = n ? 0 : 255;
|
|
24060
|
-
return `rgb(${Math.round(e.r + (a - e.r) * i)} ${Math.round(e.g + (a - e.g) * i)} ${Math.round(e.b + (a - e.b) * i)})`;
|
|
24061
|
-
}, paintFrame = (e, t, n) => {
|
|
24059
|
+
}, clamp01$3 = (e) => Math.max(0, Math.min(1, e)), inkColor = (e) => `rgb(${e.r} ${e.g} ${e.b})`, inkAlpha = (e, t) => clamp01$3(1 - clamp01$3(e)) * clamp01$3(t), paintFrame = (e, t, n) => {
|
|
24062
24060
|
e.clearRect(0, 0, e.canvas.width, e.canvas.height);
|
|
24063
|
-
let i = [...t.strokes].sort((e, t) => e.depth - t.depth);
|
|
24064
|
-
for (let t of
|
|
24065
|
-
let
|
|
24066
|
-
for (let t of
|
|
24061
|
+
let i = inkColor(n.tint), a = [...t.strokes].sort((e, t) => e.depth - t.depth);
|
|
24062
|
+
for (let t of a) e.strokeStyle = i, e.globalAlpha = inkAlpha(t.ink, t.alpha), e.lineWidth = t.width, e.beginPath(), e.moveTo(t.x1, t.y1), e.lineTo(t.x2, t.y2), e.stroke();
|
|
24063
|
+
let o = [...t.dots].sort((e, t) => e.depth - t.depth);
|
|
24064
|
+
for (let t of o) e.fillStyle = i, e.globalAlpha = inkAlpha(t.ink, t.alpha), e.beginPath(), e.arc(t.x, t.y, t.radius, 0, Math.PI * 2), e.fill();
|
|
24067
24065
|
e.globalAlpha = 1;
|
|
24068
24066
|
}, TWO_PI$1 = Math.PI * 2, WORLD_RADIUS_RATIO = .38, clamp01$2 = (e) => Math.max(0, Math.min(1, e)), clamp$1 = (e, t, n) => Math.max(t, Math.min(n, e)), originOf = (e) => e.size / 2, worldRadiusOf = (e) => e.size * WORLD_RADIUS_RATIO, INK_NEAR = .05, INK_FAR = .72, shadeByDepth = (e) => INK_FAR - (INK_FAR - INK_NEAR) * clamp01$2(e), toDot = (e, t, n, i) => ({
|
|
24069
24067
|
x: e.x,
|
|
@@ -24081,11 +24079,7 @@ var clamp01$5 = (e) => Math.max(0, Math.min(1, e)), rotateX = (e, t) => {
|
|
|
24081
24079
|
width: n,
|
|
24082
24080
|
ink: clamp01$2(i),
|
|
24083
24081
|
alpha: clamp01$2(a)
|
|
24084
|
-
}), WORKING_TRAIN_BASE_COUNT = 22,
|
|
24085
|
-
64: 3,
|
|
24086
|
-
32: 3,
|
|
24087
|
-
20: 12
|
|
24088
|
-
}, WORKING_TRAIN_LENGTH = 5, WORKING_TRAIN_ARC_SPAN = .5, WORKING_BASE_RADIUS_PX = 1.6, WORKING_ORBIT_COUNT = 6, WORKING_ANGULAR_SPEED = 1.1, WORKING_ORBIT_INK_SPREAD = .3, WORKING_ORBIT_ALPHA_FLOOR = .65, WORKING_TRAIL_ALPHA_FLOOR = .35, workingOrbit = (e) => {
|
|
24082
|
+
}), WORKING_TRAIN_BASE_COUNT = 22, WORKING_MIN_TRAINS_64 = 3, WORKING_TRAIN_LENGTH = 5, WORKING_TRAIN_ARC_SPAN = .5, WORKING_BASE_RADIUS_PX = 2.2, WORKING_ORBIT_COUNT = 6, WORKING_ANGULAR_SPEED = 1.1, WORKING_ORBIT_INK_SPREAD = .3, WORKING_ORBIT_ALPHA_FLOOR = .65, WORKING_TRAIL_ALPHA_FLOOR = .35, workingOrbit = (e) => {
|
|
24089
24083
|
let t = e * 31 + 7;
|
|
24090
24084
|
return {
|
|
24091
24085
|
tilt: (hashUnit(t) - .5) * Math.PI,
|
|
@@ -24094,22 +24088,54 @@ var clamp01$5 = (e) => Math.max(0, Math.min(1, e)), rotateX = (e, t) => {
|
|
|
24094
24088
|
speedFactor: .6 + 1.3 * hashUnit(t + 9),
|
|
24095
24089
|
weight: .35 + .65 * hashUnit(t + 15)
|
|
24096
24090
|
};
|
|
24097
|
-
},
|
|
24098
|
-
|
|
24099
|
-
|
|
24100
|
-
|
|
24101
|
-
|
|
24102
|
-
|
|
24103
|
-
|
|
24091
|
+
}, WORKING_SMALL_LAYOUT = {
|
|
24092
|
+
32: {
|
|
24093
|
+
orbits: 4,
|
|
24094
|
+
trainLength: 6,
|
|
24095
|
+
arcSpan: 1
|
|
24096
|
+
},
|
|
24097
|
+
20: {
|
|
24098
|
+
orbits: 3,
|
|
24099
|
+
trainLength: 7,
|
|
24100
|
+
arcSpan: 1.25
|
|
24101
|
+
}
|
|
24102
|
+
}, WORKING_SMALL_ORBIT_TILT = .5, WORKING_PATH_SEGMENTS = 24, WORKING_PATH_WIDTH_PX = .8, WORKING_PATH_INK = .5, WORKING_PATH_ALPHA = .45, WORKING_SMALL_ORBIT_RADIUS = .85, WORKING_SMALL_SPEEDS = [
|
|
24103
|
+
.8,
|
|
24104
|
+
1.15,
|
|
24105
|
+
1.45,
|
|
24106
|
+
1
|
|
24107
|
+
], workingSmallOrbit = (e, t) => ({
|
|
24108
|
+
...workingOrbit(e),
|
|
24109
|
+
tilt: WORKING_SMALL_ORBIT_TILT,
|
|
24110
|
+
roll: e / t * Math.PI,
|
|
24111
|
+
orbitRadiusFactor: WORKING_SMALL_ORBIT_RADIUS,
|
|
24112
|
+
speedFactor: WORKING_SMALL_SPEEDS[e % WORKING_SMALL_SPEEDS.length]
|
|
24113
|
+
}), working = (e, t) => {
|
|
24114
|
+
let n = modeSizing(t.size, t.density, t.dotScale), i = originOf(t), a = worldRadiusOf(t), o = WORKING_SMALL_LAYOUT[t.size], s = Math.max(1, Math.round(2 * t.density)), c = o ? o.orbits * s : Math.max(WORKING_MIN_TRAINS_64, n.count(WORKING_TRAIN_BASE_COUNT)), l = o ? o.trainLength : WORKING_TRAIN_LENGTH, u = (o ? o.arcSpan : WORKING_TRAIN_ARC_SPAN) / (l - 1), f = [];
|
|
24115
|
+
for (let t = 0; t < c; t += 1) {
|
|
24116
|
+
let c = o ? workingSmallOrbit(t % o.orbits, o.orbits) : workingOrbit(t % WORKING_ORBIT_COUNT), p = (o ? Math.floor(t / o.orbits) / s * TWO_PI$1 + t % o.orbits * .9 : hashUnit(t * 5 + 1) * TWO_PI$1) + e * WORKING_ANGULAR_SPEED * c.speedFactor, h = a * c.orbitRadiusFactor;
|
|
24117
|
+
for (let e = 0; e < l; e += 1) {
|
|
24118
|
+
let o = p - e * u, s = project(rotateZ(rotateX({
|
|
24119
|
+
x: Math.cos(o) * h,
|
|
24104
24120
|
y: 0,
|
|
24105
|
-
z: Math.sin(
|
|
24106
|
-
},
|
|
24107
|
-
|
|
24121
|
+
z: Math.sin(o) * h
|
|
24122
|
+
}, c.tilt), c.roll), i, a), S = t * 13 + e * 7 + 2, C = 1 - e / (l - 1), k = shadeByDepth(s.depth) + (hashUnit(S) - .5) * .08 - (c.weight - .5) * WORKING_ORBIT_INK_SPREAD, R = (WORKING_TRAIL_ALPHA_FLOOR + (1 - WORKING_TRAIL_ALPHA_FLOOR) * C) * (WORKING_ORBIT_ALPHA_FLOOR + (1 - WORKING_ORBIT_ALPHA_FLOOR) * c.weight), te = n.radius(WORKING_BASE_RADIUS_PX) * (.9 + .25 * hashUnit(S + 3));
|
|
24123
|
+
f.push(toDot(s, te, k, R));
|
|
24108
24124
|
}
|
|
24109
24125
|
}
|
|
24110
24126
|
return {
|
|
24111
|
-
dots:
|
|
24112
|
-
strokes:
|
|
24127
|
+
dots: f,
|
|
24128
|
+
strokes: o ? Array.from({ length: o.orbits }, (e, t) => {
|
|
24129
|
+
let s = workingSmallOrbit(t, o.orbits), c = a * s.orbitRadiusFactor, l = Array.from({ length: 25 }, (e, t) => {
|
|
24130
|
+
let n = t / WORKING_PATH_SEGMENTS * TWO_PI$1;
|
|
24131
|
+
return project(rotateZ(rotateX({
|
|
24132
|
+
x: Math.cos(n) * c,
|
|
24133
|
+
y: 0,
|
|
24134
|
+
z: Math.sin(n) * c
|
|
24135
|
+
}, s.tilt), s.roll), i, a);
|
|
24136
|
+
});
|
|
24137
|
+
return l.slice(1).map((e, t) => toStroke(l[t], e, n.radius(WORKING_PATH_WIDTH_PX), WORKING_PATH_INK, WORKING_PATH_ALPHA));
|
|
24138
|
+
}).flat() : []
|
|
24113
24139
|
};
|
|
24114
24140
|
}, SEARCHING_BASE_COUNT = 150, SEARCHING_BASE_RADIUS_PX = 1.5, SEARCHING_BAND_HALF_WIDTH = .42, SEARCHING_SWEEP_SPEED = 1.15, SEARCHING_SPIN_SPEED = .18, SEARCHING_TILT = -.55, SEARCHING_ARC_SEGMENTS = 10, SEARCHING_ARC_LATITUDE_SPAN = .92, SEARCHING_BAND_INK_BOOST = .75, SEARCHING_BAND_ALPHA_BOOST = .35, SEARCHING_BAND_RADIUS_BOOST = 1.3, SEARCHING_ARC_STROKE_RADIUS = 2.2, SEARCHING_ARC_INK = 0, SEARCHING_ARC_ALPHA = .7, angleDistance = (e, t) => {
|
|
24115
24141
|
let n = Math.abs(e - t) % TWO_PI$1;
|
|
@@ -24130,7 +24156,7 @@ var clamp01$5 = (e) => Math.max(0, Math.min(1, e)), rotateX = (e, t) => {
|
|
|
24130
24156
|
dots: c,
|
|
24131
24157
|
strokes: Array.from({ length: SEARCHING_ARC_SEGMENTS }, (e, t) => toStroke(l[t], l[t + 1], u, SEARCHING_ARC_INK, SEARCHING_ARC_ALPHA))
|
|
24132
24158
|
};
|
|
24133
|
-
}, SOLVING_BASE_COUNT = 130, SOLVING_BASE_RADIUS_PX = 1.5, SOLVING_TIER_COUNT = 4, SOLVING_TURN_DURATION = .16, SOLVING_TURN_GAP = .3, SOLVING_HOLD_GAP = .55, SOLVING_TILT = -.5, SOLVING_LANDMARKS_PER_TIER = 3, SOLVING_LANDMARK_RADIUS_PX = 3.1, SOLVING_LANDMARK_INK_BOOST = .45, SOLVING_LANDMARK_ALPHA = .9, SOLVING_SEAM_SEGMENTS = 12, SOLVING_SEAM_STROKE_RADIUS = 1.05, SOLVING_SEAM_INK = .15, SOLVING_SEAM_ALPHA = .5, solvingTurnStart = (e) => e * SOLVING_TURN_GAP, solvingTurnEnd = (e) => solvingTurnStart(e) + SOLVING_TURN_DURATION, SOLVING_HOLD_START = solvingTurnEnd(SOLVING_TIER_COUNT - 1) + SOLVING_HOLD_GAP, solvingReturnStart = (e) => SOLVING_HOLD_START + (SOLVING_TIER_COUNT - 1 - e) * SOLVING_TURN_GAP, solvingReturnEnd = (e) => solvingReturnStart(e) + SOLVING_TURN_DURATION, SOLVING_CYCLE = solvingReturnEnd(0) + SOLVING_HOLD_GAP, solvingTierTurn = (e, t) => {
|
|
24159
|
+
}, SOLVING_BASE_COUNT = 130, SOLVING_BASE_RADIUS_PX = 1.5, SOLVING_TIER_COUNT = 4, SOLVING_TURN_DURATION = .16, SOLVING_TURN_GAP = .3, SOLVING_HOLD_GAP = .55, SOLVING_TILT = -.5, SOLVING_LANDMARKS_PER_TIER = 3, SOLVING_LANDMARK_PHASE = hashUnit(5) * TWO_PI$1, SOLVING_LANDMARK_RADIUS_PX = 3.1, SOLVING_LANDMARK_INK_BOOST = .45, SOLVING_LANDMARK_ALPHA = .9, SOLVING_MERIDIAN_POINTS_PER_TIER = 3, SOLVING_MERIDIAN_WIDTH_PX = 1.6, SOLVING_MERIDIAN_INK_BOOST = .35, SOLVING_MERIDIAN_ALPHA = .85, SOLVING_MERIDIAN_Y_LIMIT = .9, SOLVING_SEAM_SEGMENTS = 12, SOLVING_SEAM_STROKE_RADIUS = 1.05, SOLVING_SEAM_INK = .15, SOLVING_SEAM_ALPHA = .5, solvingTurnStart = (e) => e * SOLVING_TURN_GAP, solvingTurnEnd = (e) => solvingTurnStart(e) + SOLVING_TURN_DURATION, SOLVING_HOLD_START = solvingTurnEnd(SOLVING_TIER_COUNT - 1) + SOLVING_HOLD_GAP, solvingReturnStart = (e) => SOLVING_HOLD_START + (SOLVING_TIER_COUNT - 1 - e) * SOLVING_TURN_GAP, solvingReturnEnd = (e) => solvingReturnStart(e) + SOLVING_TURN_DURATION, SOLVING_CYCLE = solvingReturnEnd(0) + SOLVING_HOLD_GAP, solvingTierTurn = (e, t) => {
|
|
24134
24160
|
let n = solvingTurnStart(e), i = solvingTurnEnd(e), a = solvingReturnStart(e), o = solvingReturnEnd(e);
|
|
24135
24161
|
return t <= n ? 0 : t < i ? easeOutCubic((t - n) / SOLVING_TURN_DURATION) : t < a ? 1 : t < o ? 1 - easeInOutCubic((t - a) / SOLVING_TURN_DURATION) : 0;
|
|
24136
24162
|
}, solvingTierOf = (e) => clamp$1(Math.floor((1 - e) / 2 * SOLVING_TIER_COUNT), 0, SOLVING_TIER_COUNT - 1), solvingTierDirection = (e) => hashUnit(e * 53 + 21) < .5 ? -1 : 1, solvingTierCenterYUnit = (e) => 1 - (2 * e + 1) / SOLVING_TIER_COUNT, solvingSeamYUnit = (e) => 1 - 2 * (e + 1) / SOLVING_TIER_COUNT, solvingTurnAngle = (e, t) => solvingTierTurn(e, t) * solvingTierDirection(e) * (Math.PI / 2), solving = (e, t) => {
|
|
@@ -24138,7 +24164,7 @@ var clamp01$5 = (e) => Math.max(0, Math.min(1, e)), rotateX = (e, t) => {
|
|
|
24138
24164
|
let c = sampleSphere(t, o, a), l = project(rotateX(rotateY(c, solvingTurnAngle(solvingTierOf(a > 0 ? c.y / a : 0), s)), SOLVING_TILT), i, a), u = shadeByDepth(l.depth), f = .55 + .3 * hashUnit(t * 3 + 9);
|
|
24139
24165
|
return toDot(l, n.radius(SOLVING_BASE_RADIUS_PX), u, f);
|
|
24140
24166
|
}), l = Array.from({ length: SOLVING_TIER_COUNT * SOLVING_LANDMARKS_PER_TIER }, (e, t) => {
|
|
24141
|
-
let o = Math.floor(t / SOLVING_LANDMARKS_PER_TIER), c = t % SOLVING_LANDMARKS_PER_TIER, l = solvingTierCenterYUnit(o), u = l * a, f = Math.sqrt(Math.max(0, 1 - l * l)) * a, p =
|
|
24167
|
+
let o = Math.floor(t / SOLVING_LANDMARKS_PER_TIER), c = t % SOLVING_LANDMARKS_PER_TIER, l = solvingTierCenterYUnit(o), u = l * a, f = Math.sqrt(Math.max(0, 1 - l * l)) * a, p = SOLVING_LANDMARK_PHASE + c / SOLVING_LANDMARKS_PER_TIER * TWO_PI$1, h = project(rotateX(rotateY({
|
|
24142
24168
|
x: Math.cos(p) * f,
|
|
24143
24169
|
y: u,
|
|
24144
24170
|
z: Math.sin(p) * f
|
|
@@ -24154,16 +24180,29 @@ var clamp01$5 = (e) => Math.max(0, Math.min(1, e)), rotateX = (e, t) => {
|
|
|
24154
24180
|
}, SOLVING_TILT), i, a);
|
|
24155
24181
|
});
|
|
24156
24182
|
return Array.from({ length: SOLVING_SEAM_SEGMENTS }, (e, t) => toStroke(c[t], c[t + 1], u, SOLVING_SEAM_INK, SOLVING_SEAM_ALPHA));
|
|
24183
|
+
}).flat(), p = n.radius(SOLVING_MERIDIAN_WIDTH_PX), h = Array.from({ length: SOLVING_TIER_COUNT * SOLVING_LANDMARKS_PER_TIER }, (e, t) => {
|
|
24184
|
+
let n = Math.floor(t / SOLVING_LANDMARKS_PER_TIER), o = SOLVING_LANDMARK_PHASE + t % SOLVING_LANDMARKS_PER_TIER / SOLVING_LANDMARKS_PER_TIER * TWO_PI$1, c = Math.min(SOLVING_MERIDIAN_Y_LIMIT, 1 - 2 * n / SOLVING_TIER_COUNT), l = Math.max(-.9, 1 - 2 * (n + 1) / SOLVING_TIER_COUNT), u = Array.from({ length: SOLVING_MERIDIAN_POINTS_PER_TIER }, (e, t) => {
|
|
24185
|
+
let u = c + (l - c) * t / (SOLVING_MERIDIAN_POINTS_PER_TIER - 1), f = Math.sqrt(Math.max(0, 1 - u * u)) * a;
|
|
24186
|
+
return project(rotateX(rotateY({
|
|
24187
|
+
x: Math.cos(o) * f,
|
|
24188
|
+
y: u * a,
|
|
24189
|
+
z: Math.sin(o) * f
|
|
24190
|
+
}, solvingTurnAngle(n, s)), SOLVING_TILT), i, a);
|
|
24191
|
+
});
|
|
24192
|
+
return u.slice(1).map((e, t) => {
|
|
24193
|
+
let n = u[t];
|
|
24194
|
+
return toStroke(n, e, p, shadeByDepth((n.depth + e.depth) / 2) - SOLVING_MERIDIAN_INK_BOOST, SOLVING_MERIDIAN_ALPHA);
|
|
24195
|
+
});
|
|
24157
24196
|
}).flat();
|
|
24158
24197
|
return {
|
|
24159
24198
|
dots: [...c, ...l],
|
|
24160
|
-
strokes: f
|
|
24199
|
+
strokes: [...f, ...h]
|
|
24161
24200
|
};
|
|
24162
24201
|
}, LISTENING_RING_COUNT = {
|
|
24163
24202
|
64: 5,
|
|
24164
24203
|
32: 4,
|
|
24165
24204
|
20: 3
|
|
24166
|
-
}, LISTENING_DOTS_PER_RING_BASE = 26, LISTENING_MIN_DOTS_PER_RING = 10, LISTENING_BASE_RADIUS_PX = 1.5, LISTENING_WAVE_SPEED = .6, LISTENING_SWELL = .
|
|
24205
|
+
}, LISTENING_DOTS_PER_RING_BASE = 26, LISTENING_MIN_DOTS_PER_RING = 10, LISTENING_BASE_RADIUS_PX = 1.5, LISTENING_WAVE_SPEED = .6, LISTENING_SWELL = .3, LISTENING_LIFT_INK = .45, LISTENING_SPIN_SPEED = .12, LISTENING_TILT = -.1, LISTENING_Y_SPAN = .86, listeningRing = (e, t, n) => {
|
|
24167
24206
|
let i = (-1 + (2 * e + 1) / t) * LISTENING_Y_SPAN * n;
|
|
24168
24207
|
return {
|
|
24169
24208
|
y: i,
|
|
@@ -24172,15 +24211,15 @@ var clamp01$5 = (e) => Math.max(0, Math.min(1, e)), rotateX = (e, t) => {
|
|
|
24172
24211
|
wave: (n) => (Math.sin(TWO_PI$1 * (e / t - n * LISTENING_WAVE_SPEED)) + 1) / 2
|
|
24173
24212
|
};
|
|
24174
24213
|
}, listening = (e, t) => {
|
|
24175
|
-
let n = modeSizing(t.size, t.density, t.dotScale), i = originOf(t), a = worldRadiusOf(t), o = LISTENING_RING_COUNT[t.size], s =
|
|
24214
|
+
let n = modeSizing(t.size, t.density, t.dotScale), i = originOf(t), a = worldRadiusOf(t), o = LISTENING_RING_COUNT[t.size], s = Math.max(LISTENING_MIN_DOTS_PER_RING, n.countAlongPath(LISTENING_DOTS_PER_RING_BASE));
|
|
24176
24215
|
return {
|
|
24177
|
-
dots: Array.from({ length: o }, (t,
|
|
24178
|
-
let l = listeningRing(
|
|
24179
|
-
return Array.from({ length:
|
|
24180
|
-
let
|
|
24181
|
-
x: Math.cos(
|
|
24216
|
+
dots: Array.from({ length: o }, (t, c) => {
|
|
24217
|
+
let l = listeningRing(c, o, a), u = l.wave(e);
|
|
24218
|
+
return Array.from({ length: s }, (t, o) => {
|
|
24219
|
+
let c = o / s * TWO_PI$1 + l.phase, f = project(rotateY(rotateX({
|
|
24220
|
+
x: Math.cos(c) * l.ringRadius,
|
|
24182
24221
|
y: l.y,
|
|
24183
|
-
z: Math.sin(
|
|
24222
|
+
z: Math.sin(c) * l.ringRadius
|
|
24184
24223
|
}, LISTENING_TILT), e * LISTENING_SPIN_SPEED), i, a), p = shadeByDepth(f.depth) - u * LISTENING_LIFT_INK, h = .6 + u * .3;
|
|
24185
24224
|
return toDot(f, n.radius(LISTENING_BASE_RADIUS_PX) * (1 + u * LISTENING_SWELL), p, h);
|
|
24186
24225
|
});
|
|
@@ -24194,7 +24233,7 @@ var clamp01$5 = (e) => Math.max(0, Math.min(1, e)), rotateX = (e, t) => {
|
|
|
24194
24233
|
}), squaredDistance = (e, t) => {
|
|
24195
24234
|
let n = e.x - t.x, i = e.y - t.y, a = e.z - t.z;
|
|
24196
24235
|
return n * n + i * i + a * a;
|
|
24197
|
-
}, NODE_BASE_COUNT =
|
|
24236
|
+
}, NODE_BASE_COUNT = 10, MIN_NODE_COUNT = 6, NEIGHBOR_COUNT = 2, NODE_BASE_RADIUS = 3.4, PULSE_BASE_RADIUS = 1.4, EDGE_BASE_WIDTH = 1.1, NODE_ROTATE_SPEED = .35, NODE_TILT = .45, EDGE_FLICKER_SPEED = .5, EDGE_MIN_ALPHA = .25, PULSE_SPEED = .6, nearestNeighborEdges = (e, t) => {
|
|
24198
24237
|
let n = e.map((e, t) => t), i = n.flatMap((i) => n.filter((e) => e !== i).sort((t, n) => squaredDistance(e[i], e[t]) - squaredDistance(e[i], e[n])).slice(0, t).map((e) => i < e ? [i, e] : [e, i]));
|
|
24199
24238
|
return i.filter(([e, t], n) => i.findIndex(([n, i]) => n === e && i === t) === n);
|
|
24200
24239
|
}, connecting = (e, t) => {
|
|
@@ -24232,51 +24271,59 @@ var clamp01$5 = (e) => Math.max(0, Math.min(1, e)), rotateX = (e, t) => {
|
|
|
24232
24271
|
dots: [...l, ...p],
|
|
24233
24272
|
strokes: f
|
|
24234
24273
|
};
|
|
24235
|
-
}, STRAND_COUNT = 3, STRAND_POINTS_BASE_COUNT =
|
|
24236
|
-
|
|
24237
|
-
|
|
24238
|
-
|
|
24239
|
-
|
|
24240
|
-
|
|
24241
|
-
|
|
24274
|
+
}, STRAND_COUNT = 3, STRAND_POINTS_BASE_COUNT = 40, MIN_STRAND_POINTS = 16, STRAND_INCLINATION = .6, STRAND_WAVE_COUNT = 3, STRAND_WAVE_AMPLITUDE = .12, STRAND_WAVE_SPEED = .9, STRAND_ROTATE_SPEED = .3, STRAND_TILT = 1.1, STRAND_DOT_BASE_RADIUS = 1.6, STRAND_STROKE_BASE_WIDTH = 1.4, STRAND_STROKE_SIZE_FACTOR = {
|
|
24275
|
+
64: 1,
|
|
24276
|
+
32: 1.2,
|
|
24277
|
+
20: 1.5
|
|
24278
|
+
}, STRAND_DOT_SIZE_FACTOR = {
|
|
24279
|
+
64: 1,
|
|
24280
|
+
32: .85,
|
|
24281
|
+
20: .7
|
|
24282
|
+
}, STRAND_DEPTH_INK = .45, STRAND_SHADE_STEP = .1, strandBaseAngle = (e) => e / STRAND_COUNT * Math.PI * 2, strandPoint = (e, t, n, i, a) => {
|
|
24283
|
+
let o = t / (n - 1) * Math.PI * 2, s = STRAND_WAVE_AMPLITUDE * Math.sin(o * STRAND_WAVE_COUNT + a * STRAND_WAVE_SPEED + strandBaseAngle(e));
|
|
24284
|
+
return rotateX(rotateY(rotateX({
|
|
24285
|
+
x: i * Math.cos(s) * Math.cos(o),
|
|
24286
|
+
y: i * Math.sin(s),
|
|
24287
|
+
z: i * Math.cos(s) * Math.sin(o)
|
|
24288
|
+
}, STRAND_INCLINATION), strandBaseAngle(e) + a * STRAND_ROTATE_SPEED), STRAND_TILT);
|
|
24242
24289
|
}, weaving = (e, t) => {
|
|
24243
|
-
let { sizing: n, originPx: i, sphereRadius: a } = sphereGeometry(t), o = Math.max(MIN_STRAND_POINTS, n.
|
|
24290
|
+
let { sizing: n, originPx: i, sphereRadius: a } = sphereGeometry(t), o = Math.max(MIN_STRAND_POINTS, n.countAlongPath(STRAND_POINTS_BASE_COUNT)), s = Array.from({ length: STRAND_COUNT }, (t, n) => Array.from({ length: o }, (t, s) => project(strandPoint(n, s, o, a, e), i, a)));
|
|
24244
24291
|
return {
|
|
24245
|
-
dots: s.flatMap((e,
|
|
24292
|
+
dots: s.flatMap((e, i) => e.map((e) => ({
|
|
24246
24293
|
x: e.x,
|
|
24247
24294
|
y: e.y,
|
|
24248
24295
|
depth: e.depth,
|
|
24249
|
-
radius: n.radius(STRAND_DOT_BASE_RADIUS),
|
|
24250
|
-
ink: clamp01$1(1 - e.depth *
|
|
24296
|
+
radius: n.radius(STRAND_DOT_BASE_RADIUS) * STRAND_DOT_SIZE_FACTOR[t.size],
|
|
24297
|
+
ink: clamp01$1((1 - e.depth) * STRAND_DEPTH_INK + i * STRAND_SHADE_STEP),
|
|
24251
24298
|
alpha: .55 + e.depth * .4
|
|
24252
24299
|
}))),
|
|
24253
|
-
strokes: s.flatMap((e,
|
|
24254
|
-
let
|
|
24300
|
+
strokes: s.flatMap((e, i) => e.slice(1).map((a, o) => {
|
|
24301
|
+
let s = e[o], c = (s.depth + a.depth) / 2;
|
|
24255
24302
|
return {
|
|
24256
|
-
x1:
|
|
24257
|
-
y1:
|
|
24258
|
-
x2:
|
|
24259
|
-
y2:
|
|
24260
|
-
depth:
|
|
24261
|
-
width: n.radius(STRAND_STROKE_BASE_WIDTH),
|
|
24262
|
-
ink: clamp01$1(1 -
|
|
24263
|
-
alpha: .6 +
|
|
24303
|
+
x1: s.x,
|
|
24304
|
+
y1: s.y,
|
|
24305
|
+
x2: a.x,
|
|
24306
|
+
y2: a.y,
|
|
24307
|
+
depth: c,
|
|
24308
|
+
width: n.radius(STRAND_STROKE_BASE_WIDTH) * STRAND_STROKE_SIZE_FACTOR[t.size],
|
|
24309
|
+
ink: clamp01$1((1 - c) * STRAND_DEPTH_INK + i * STRAND_SHADE_STEP),
|
|
24310
|
+
alpha: .6 + c * .35
|
|
24264
24311
|
};
|
|
24265
24312
|
}))
|
|
24266
24313
|
};
|
|
24267
|
-
}, TWO_PI = Math.PI * 2, FORM_RADIUS_RATIO = .4, clamp01 = (e) => Math.max(0, Math.min(1, e)), depthToInk = (e) => clamp01(1 - e), depthToAlpha = (e) => clamp01(.5 + e * .5), depthToRadiusFactor = (e) => .7 + e * .3, dotFrom = (e, t, n, i) => ({
|
|
24314
|
+
}, TWO_PI = Math.PI * 2, FORM_RADIUS_RATIO = .4, clamp01 = (e) => Math.max(0, Math.min(1, e)), FAR_INK = .6, depthToInk = (e) => clamp01((1 - e) * FAR_INK), depthToAlpha = (e) => clamp01(.5 + e * .5), depthToRadiusFactor = (e) => .7 + e * .3, dotFrom = (e, t, n, i) => ({
|
|
24268
24315
|
x: e.x,
|
|
24269
24316
|
y: e.y,
|
|
24270
24317
|
depth: e.depth,
|
|
24271
24318
|
radius: n.radius(t) * depthToRadiusFactor(e.depth) * i,
|
|
24272
24319
|
ink: depthToInk(e.depth),
|
|
24273
24320
|
alpha: depthToAlpha(e.depth)
|
|
24274
|
-
}), place = (e, t, n, i, a, o, s, c) => dotFrom(project(rotateX(rotateY(e, t), n), i, a), o, s, c), EMPTY_STROKES = [],
|
|
24275
|
-
64:
|
|
24276
|
-
32:
|
|
24277
|
-
20:
|
|
24278
|
-
}, RIBBON_HALF_WIDTH = .
|
|
24279
|
-
let n = modeSizing(t.size, t.density, t.dotScale), i = t.size * FORM_RADIUS_RATIO, a = t.size / 2, o = RIBBON_THREADS[t.size], s =
|
|
24321
|
+
}), place = (e, t, n, i, a, o, s, c) => dotFrom(project(rotateX(rotateY(e, t), n), i, a), o, s, c), EMPTY_STROKES = [], RIBBON_PER_THREAD_BASE = 36, RIBBON_BASE_DOT_RADIUS = 2.2, RIBBON_THREADS = {
|
|
24322
|
+
64: 5,
|
|
24323
|
+
32: 4,
|
|
24324
|
+
20: 3
|
|
24325
|
+
}, RIBBON_HALF_WIDTH = .3, RIBBON_AXIS_TILT = .68, RIBBON_RIPPLE_WAVES = 3, RIBBON_RIPPLE_SPEED = 1.15, RIBBON_RIPPLE_AMPLITUDE = .18, RIBBON_THREAD_JITTER = .1, RIBBON_SPIN_SPEED = .48, RIBBON_CAMERA_TILT = .45, RIBBON_EDGE_ALPHA_FLOOR = .5, RIBBON_EDGE_INK_LIFT = .22, composing = (e, t) => {
|
|
24326
|
+
let n = modeSizing(t.size, t.density, t.dotScale), i = t.size * FORM_RADIUS_RATIO, a = t.size / 2, o = RIBBON_THREADS[t.size], s = n.countAlongPath(RIBBON_PER_THREAD_BASE), c = o * s, l = [];
|
|
24280
24327
|
for (let t = 0; t < c; t += 1) {
|
|
24281
24328
|
let c = t % o, u = Math.floor(t / o), f = o > 1 ? c / (o - 1) * 2 - 1 : 0, p = u / s * TWO_PI, h = Math.sin(p * RIBBON_RIPPLE_WAVES + e * RIBBON_RIPPLE_SPEED) * RIBBON_RIPPLE_AMPLITUDE, S = f * RIBBON_HALF_WIDTH + h, C = rotateZ({
|
|
24282
24329
|
x: Math.cos(S) * Math.cos(p) * i,
|
|
@@ -24293,8 +24340,8 @@ var clamp01$5 = (e) => Math.max(0, Math.min(1, e)), rotateX = (e, t) => {
|
|
|
24293
24340
|
dots: l,
|
|
24294
24341
|
strokes: EMPTY_STROKES
|
|
24295
24342
|
};
|
|
24296
|
-
}, BREATHING_BASE_COUNT =
|
|
24297
|
-
let n = modeSizing(t.size, t.density, t.dotScale), i = t.size * BREATHING_WORLD_RADIUS_RATIO, a = t.size / 2, o = n.
|
|
24343
|
+
}, BREATHING_BASE_COUNT = 32, BREATHING_BASE_DOT_RADIUS = 1.7, BREATHING_WORLD_RADIUS_RATIO = .34, BREATHING_AMPLITUDE = .09, BREATHING_SPEED = .55, BREATHING_SHAPE_HARMONIC = 5, BREATHING_SHAPE_SPEED = .22, BREATHING_SHAPE_AMPLITUDE = .035, BREATHING_SPIN_SPEED = .12, BREATHING_TILT = .62, breathing = (e, t) => {
|
|
24344
|
+
let n = modeSizing(t.size, t.density, t.dotScale), i = t.size * BREATHING_WORLD_RADIUS_RATIO, a = t.size / 2, o = n.countAlongPath(BREATHING_BASE_COUNT), s = Math.sin(e * BREATHING_SPEED), c = [];
|
|
24298
24345
|
for (let t = 0; t < o; t += 1) {
|
|
24299
24346
|
let l = t / o * TWO_PI, u = Math.sin(l * BREATHING_SHAPE_HARMONIC + e * BREATHING_SHAPE_SPEED) * BREATHING_SHAPE_AMPLITUDE, f = 1 + s * BREATHING_AMPLITUDE + u, p = {
|
|
24300
24347
|
x: Math.cos(l) * f * i,
|
|
@@ -24307,11 +24354,11 @@ var clamp01$5 = (e) => Math.max(0, Math.min(1, e)), rotateX = (e, t) => {
|
|
|
24307
24354
|
dots: c,
|
|
24308
24355
|
strokes: EMPTY_STROKES
|
|
24309
24356
|
};
|
|
24310
|
-
}, SHAPING_BASE_COUNT =
|
|
24357
|
+
}, SHAPING_BASE_COUNT = 36, SHAPING_BASE_DOT_RADIUS = 1.7, SHAPING_CYCLE_SECONDS = 12, SHAPING_SPIN_SPEED = 2 * Math.PI / SHAPING_CYCLE_SECONDS, SHAPING_TILT = .6, polygonRadius = (e, t) => {
|
|
24311
24358
|
let n = TWO_PI / t, i = n / 2, a = (e % n + n) % n;
|
|
24312
24359
|
return Math.cos(i) / Math.cos(a - i);
|
|
24313
24360
|
}, lerp = (e, t, n) => e + (t - e) * n, shaping = (e, t) => {
|
|
24314
|
-
let n = modeSizing(t.size, t.density, t.dotScale), i = t.size * FORM_RADIUS_RATIO, a = t.size / 2, o = n.
|
|
24361
|
+
let n = modeSizing(t.size, t.density, t.dotScale), i = t.size * FORM_RADIUS_RATIO, a = t.size / 2, o = n.countAlongPath(SHAPING_BASE_COUNT), s = (e / SHAPING_CYCLE_SECONDS % 1 + 1) % 1 * 3, c = Math.min(2, Math.floor(s)), l = easeInOutCubic(s - c), u = [];
|
|
24315
24362
|
for (let t = 0; t < o; t += 1) {
|
|
24316
24363
|
let s = t / o * TWO_PI, f = polygonRadius(s, 3), p = polygonRadius(s, 4), h;
|
|
24317
24364
|
h = c === 0 ? lerp(1, f, l) : c === 1 ? lerp(f, p, l) : lerp(p, 1, l);
|
|
@@ -24347,7 +24394,7 @@ function ThinkingOrb(e, t) {
|
|
|
24347
24394
|
r: 128,
|
|
24348
24395
|
g: 128,
|
|
24349
24396
|
b: 128
|
|
24350
|
-
}, R = 2.4, te = 2, ne = /* @__PURE__ */ user_derived(() => Object.hasOwn(MODES, n()) ? n() : "working"), re = /* @__PURE__ */ user_derived(() => C.includes(i()) ? i() : 64), G = /* @__PURE__ */ user_derived(() => Math.max(.1, c())), be = /* @__PURE__ */ user_derived(() => Math.max(.1, l())), Me = /* @__PURE__ */ user_derived(() => !u() || get(Ue) ? null : u() === !0 ? GRAVITY_DEFAULTS : u()), Re = /* @__PURE__ */ state(null), Ue = /* @__PURE__ */ state(proxy(prefersReducedMotion())), it = /* @__PURE__ */ state(!0), at = /* @__PURE__ */ state(!0), ot =
|
|
24397
|
+
}, R = 2.4, te = 2, ne = /* @__PURE__ */ user_derived(() => Object.hasOwn(MODES, n()) ? n() : "working"), re = /* @__PURE__ */ user_derived(() => C.includes(i()) ? i() : 64), G = /* @__PURE__ */ user_derived(() => Math.max(.1, c())), be = /* @__PURE__ */ user_derived(() => Math.max(.1, l())), Me = /* @__PURE__ */ user_derived(() => !u() || get(Ue) ? null : u() === !0 ? GRAVITY_DEFAULTS : u()), Re = /* @__PURE__ */ state(null), Ue = /* @__PURE__ */ state(proxy(prefersReducedMotion())), it = /* @__PURE__ */ state(!0), at = /* @__PURE__ */ state(!0), ot = !1, ct = "", lt = k, ut = null, dt = 0, ft = 0, pt = /* @__PURE__ */ user_derived(() => !o() && !get(Ue) && get(it) && get(at)), mt = () => get(Ue) ? 2.4 : ft, ht = (e, t) => {
|
|
24351
24398
|
if (t.length === 0) return null;
|
|
24352
24399
|
let n = e.fillStyle;
|
|
24353
24400
|
e.fillStyle = "#000000", e.fillStyle = t;
|
|
@@ -24355,32 +24402,34 @@ function ThinkingOrb(e, t) {
|
|
|
24355
24402
|
e.fillStyle = "#ffffff", e.fillStyle = t;
|
|
24356
24403
|
let a = e.fillStyle;
|
|
24357
24404
|
return e.fillStyle = n, typeof i == "string" && i === a ? i : null;
|
|
24358
|
-
},
|
|
24405
|
+
}, gt = (e) => {
|
|
24359
24406
|
let t = getComputedStyle(e), n = t.getPropertyValue("--sui-thinking-orb-color").trim(), i = t.color.trim();
|
|
24360
24407
|
return {
|
|
24361
24408
|
declared: n,
|
|
24362
24409
|
inherited: i,
|
|
24363
24410
|
key: `${n}|${i}`
|
|
24364
24411
|
};
|
|
24365
|
-
},
|
|
24412
|
+
}, _t = (e) => {
|
|
24366
24413
|
if (s()) return s();
|
|
24367
|
-
if (get(Re) === null) return
|
|
24368
|
-
let { declared: t, inherited: n, key: i } =
|
|
24369
|
-
if (i ===
|
|
24370
|
-
|
|
24371
|
-
let a =
|
|
24372
|
-
return
|
|
24414
|
+
if (get(Re) === null) return lt;
|
|
24415
|
+
let { declared: t, inherited: n, key: i } = gt(get(Re));
|
|
24416
|
+
if (i === ct) return lt;
|
|
24417
|
+
ct = i;
|
|
24418
|
+
let a = ht(e, t) ?? ht(e, n);
|
|
24419
|
+
return lt = (a === null ? null : parseCssColor(a)) ?? k, lt;
|
|
24420
|
+
}, vt = () => {
|
|
24421
|
+
get(pt) || get(Me) === null || Ct(mt());
|
|
24373
24422
|
}, yt = () => {
|
|
24374
|
-
get(
|
|
24423
|
+
get(pt) || s() || get(Re) === null || gt(get(Re)).key !== ct && Ct(mt());
|
|
24375
24424
|
}, bt = (e) => {
|
|
24376
24425
|
if (get(Re) === null || !u()) return;
|
|
24377
24426
|
let t = get(Re).getBoundingClientRect();
|
|
24378
|
-
|
|
24427
|
+
ut = {
|
|
24379
24428
|
x: e.clientX - t.left,
|
|
24380
24429
|
y: e.clientY - t.top
|
|
24381
|
-
},
|
|
24430
|
+
}, vt();
|
|
24382
24431
|
}, xt = () => {
|
|
24383
|
-
|
|
24432
|
+
ut = null, vt();
|
|
24384
24433
|
}, St = () => typeof window > "u" ? 1 : Math.min(2, window.devicePixelRatio ?? 1), Ct = (e) => {
|
|
24385
24434
|
if (get(Re) === null) return;
|
|
24386
24435
|
let t = get(Re).getContext("2d");
|
|
@@ -24392,18 +24441,15 @@ function ThinkingOrb(e, t) {
|
|
|
24392
24441
|
density: get(G),
|
|
24393
24442
|
dotScale: get(be)
|
|
24394
24443
|
}), o = get(Me);
|
|
24395
|
-
paintFrame(t, o === null ? a : attract(a,
|
|
24396
|
-
dark: get(ot),
|
|
24397
|
-
tint: vt(t)
|
|
24398
|
-
}), ct || (ct = !0, S()?.());
|
|
24444
|
+
paintFrame(t, o === null ? a : attract(a, ut, o), { tint: _t(t) }), ot || (ot = !0, S()?.());
|
|
24399
24445
|
};
|
|
24400
24446
|
user_effect(() => {
|
|
24401
|
-
if (Ct(
|
|
24447
|
+
if (Ct(mt()), !get(pt)) return;
|
|
24402
24448
|
let e = null, t = (n) => {
|
|
24403
24449
|
let i = e === null ? 0 : (n - e) / 1e3;
|
|
24404
|
-
e = n,
|
|
24450
|
+
e = n, ft += i * a(), Ct(ft), dt = requestAnimationFrame(t);
|
|
24405
24451
|
};
|
|
24406
|
-
return
|
|
24452
|
+
return dt = requestAnimationFrame(t), () => cancelAnimationFrame(dt);
|
|
24407
24453
|
}), onMount(() => {
|
|
24408
24454
|
if (get(Re) === null) return;
|
|
24409
24455
|
let e = null;
|
|
@@ -24414,24 +24460,19 @@ function ThinkingOrb(e, t) {
|
|
|
24414
24460
|
set(at, document.visibilityState !== "hidden");
|
|
24415
24461
|
};
|
|
24416
24462
|
document.addEventListener("visibilitychange", t);
|
|
24417
|
-
let n =
|
|
24418
|
-
|
|
24419
|
-
|
|
24420
|
-
n();
|
|
24421
|
-
let i = null;
|
|
24422
|
-
typeof MutationObserver < "u" && (i = new MutationObserver(n), i.observe(document.documentElement, {
|
|
24423
|
-
attributes: !0,
|
|
24424
|
-
attributeFilter: ["data-theme"]
|
|
24425
|
-
}));
|
|
24426
|
-
let a = (e) => {
|
|
24463
|
+
let n = null;
|
|
24464
|
+
typeof MutationObserver < "u" && (n = new MutationObserver(yt), n.observe(document.documentElement, { attributes: !0 }), n.observe(document.body, { attributes: !0 }));
|
|
24465
|
+
let i = (e) => {
|
|
24427
24466
|
set(Ue, e.matches, !0);
|
|
24428
|
-
},
|
|
24429
|
-
typeof window.matchMedia == "function" && (
|
|
24430
|
-
let
|
|
24431
|
-
|
|
24432
|
-
|
|
24433
|
-
|
|
24434
|
-
|
|
24467
|
+
}, a = null;
|
|
24468
|
+
typeof window.matchMedia == "function" && (a = window.matchMedia("(prefers-reduced-motion: reduce)"), a.addEventListener("change", i));
|
|
24469
|
+
let o = null;
|
|
24470
|
+
typeof window.matchMedia == "function" && (o = window.matchMedia("(prefers-color-scheme: dark)"), o.addEventListener("change", yt));
|
|
24471
|
+
let s = (e) => {
|
|
24472
|
+
e.propertyName !== "color" && e.propertyName !== "--sui-thinking-orb-color" || yt();
|
|
24473
|
+
};
|
|
24474
|
+
return document.addEventListener("transitionend", s), () => {
|
|
24475
|
+
e?.disconnect(), document.removeEventListener("visibilitychange", t), document.removeEventListener("transitionend", s), n?.disconnect(), a?.removeEventListener("change", i), o?.removeEventListener("change", yt);
|
|
24435
24476
|
};
|
|
24436
24477
|
});
|
|
24437
24478
|
var wt = {
|