@fusion.dev/helix 0.9.0 → 0.10.1
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/custom-elements.json +152 -5
- package/dist/chat/message/chat-message.css.js +2 -0
- package/dist/orb/root/orb-color.d.ts +19 -0
- package/dist/orb/root/orb-color.js +25 -0
- package/dist/orb/root/orb-root.d.ts +37 -8
- package/dist/orb/root/orb-root.js +28 -14
- package/dist/orb/root/orb-shapes.d.ts +27 -3
- package/dist/orb/root/orb-shapes.js +143 -12
- package/package.json +6 -6
- package/types/jsx.d.ts +38 -18
- package/types/vue.d.ts +1 -1
package/custom-elements.json
CHANGED
|
@@ -54613,6 +54613,40 @@
|
|
|
54613
54613
|
}
|
|
54614
54614
|
]
|
|
54615
54615
|
},
|
|
54616
|
+
{
|
|
54617
|
+
"kind": "javascript-module",
|
|
54618
|
+
"path": "src/orb/root/orb-color.ts",
|
|
54619
|
+
"declarations": [
|
|
54620
|
+
{
|
|
54621
|
+
"kind": "function",
|
|
54622
|
+
"name": "readColor",
|
|
54623
|
+
"return": {
|
|
54624
|
+
"type": {
|
|
54625
|
+
"text": "[number, number, number]"
|
|
54626
|
+
}
|
|
54627
|
+
},
|
|
54628
|
+
"parameters": [
|
|
54629
|
+
{
|
|
54630
|
+
"name": "value",
|
|
54631
|
+
"type": {
|
|
54632
|
+
"text": "string"
|
|
54633
|
+
}
|
|
54634
|
+
}
|
|
54635
|
+
],
|
|
54636
|
+
"description": "A computed color as three sRGB bytes, whatever space it was written in.\n\n**Painting it is the only way to read it.** A color-typed property is\nresolved before it is reported, but resolved is not the same as converted:\nChrome hands back `lab(100 0 0)` for a token built through `oklab`, and this\nused to scrape the first three numbers out of that and call them red, green\nand blue. White arrived as `rgb(100, 0, 0)`. In light mode the near dots were\n`lab(0 0 0)`, which scrapes to black and looks right, so only dark mode showed\nit: dark red mixed toward black, on a near-black ground.\n\nA 1x1 fill and `getImageData` is a readback, so the answer is cached against\nthe string it came from. There are two per orb and they change when the theme\ndoes."
|
|
54637
|
+
}
|
|
54638
|
+
],
|
|
54639
|
+
"exports": [
|
|
54640
|
+
{
|
|
54641
|
+
"kind": "js",
|
|
54642
|
+
"name": "readColor",
|
|
54643
|
+
"declaration": {
|
|
54644
|
+
"name": "readColor",
|
|
54645
|
+
"module": "src/orb/root/orb-color.ts"
|
|
54646
|
+
}
|
|
54647
|
+
}
|
|
54648
|
+
]
|
|
54649
|
+
},
|
|
54616
54650
|
{
|
|
54617
54651
|
"kind": "javascript-module",
|
|
54618
54652
|
"path": "src/orb/root/orb-root.css.ts",
|
|
@@ -54639,7 +54673,7 @@
|
|
|
54639
54673
|
"declarations": [
|
|
54640
54674
|
{
|
|
54641
54675
|
"kind": "class",
|
|
54642
|
-
"description": "A cloud of dots
|
|
54676
|
+
"description": "A cloud of dots, drawn to a canvas, with one shape per state. `connecting`\nand `thinking` are the same leaning sash and differ in how agitated it is;\n`waiting` and `done` are the same settled ball at different tempos, which is\nthe difference between not having started and having finished. `fetching` is\na globe with a light going round it, `listening` a closed sphere with a\nripple crossing it, and `working` a ring.\n\n**None of them is a separate drawing.** Each is the same banded grid given\ndifferent numbers, so changing state interpolates the numbers and every frame\nin between is a whole shape. A loader that cuts between pictures says the\nwork restarted; one that carries a shape into the next says it moved on.\n\n**A change is measured before it is played.** Two states differing in one\nsmall number are given less time than a sash becoming a ring, and the\nsilhouette leads what the shape is doing, so a light is never seen orbiting\nsomething that has not finished becoming round.\n\n**Nothing spins.** The whole cloud holds still and everything that moves is\nmoving inside it, which is what makes it read as thought rather than as a\nthing being rotated. The one exception is the light, which travels because a\nring of evenly spaced dots is unchanged by rotation: without something fixed\nin space passing over them, a state that turns has nothing a reader can see\nturning.\n\n**The palette is read from the tokens**, not given as colors: a dot's ink is\nmixed toward the ground by how far away it is, and both ends come from\n`--orb-color` and `--orb-ground`. That is what makes depth survive a theme\nchange without the consumer restating anything.\n\n**It stops when nobody is looking**, off screen and in a background tab, and\n`prefers-reduced-motion` gets one still frame rather than an empty box.",
|
|
54643
54677
|
"name": "HelixOrb",
|
|
54644
54678
|
"cssProperties": [
|
|
54645
54679
|
{
|
|
@@ -54788,6 +54822,16 @@
|
|
|
54788
54822
|
"privacy": "private",
|
|
54789
54823
|
"default": "0"
|
|
54790
54824
|
},
|
|
54825
|
+
{
|
|
54826
|
+
"kind": "field",
|
|
54827
|
+
"name": "reach",
|
|
54828
|
+
"type": {
|
|
54829
|
+
"text": "number"
|
|
54830
|
+
},
|
|
54831
|
+
"privacy": "private",
|
|
54832
|
+
"default": "0",
|
|
54833
|
+
"description": "How far the current change travels, `0` to `1`."
|
|
54834
|
+
},
|
|
54791
54835
|
{
|
|
54792
54836
|
"kind": "field",
|
|
54793
54837
|
"name": "phase",
|
|
@@ -54839,6 +54883,16 @@
|
|
|
54839
54883
|
},
|
|
54840
54884
|
"description": "Begins a transition from whatever is on the screen right now."
|
|
54841
54885
|
},
|
|
54886
|
+
{
|
|
54887
|
+
"kind": "field",
|
|
54888
|
+
"name": "span",
|
|
54889
|
+
"type": {
|
|
54890
|
+
"text": "number"
|
|
54891
|
+
},
|
|
54892
|
+
"privacy": "private",
|
|
54893
|
+
"description": "How long this particular change is given.\n\n**Near states cross quickly and far ones are not hurried.** One length for\nevery pair read as rushed going from `waiting` to `done`, which differ in\ntwo small numbers, and slack going from `thinking` to `working`, which is a\nsash becoming a ring.",
|
|
54894
|
+
"readonly": true
|
|
54895
|
+
},
|
|
54842
54896
|
{
|
|
54843
54897
|
"kind": "field",
|
|
54844
54898
|
"name": "progress",
|
|
@@ -55151,7 +55205,7 @@
|
|
|
55151
55205
|
"slug": "sizes"
|
|
55152
55206
|
},
|
|
55153
55207
|
{
|
|
55154
|
-
"description": "The
|
|
55208
|
+
"description": "The seven shapes, side by side.",
|
|
55155
55209
|
"slug": "states"
|
|
55156
55210
|
}
|
|
55157
55211
|
],
|
|
@@ -55190,9 +55244,9 @@
|
|
|
55190
55244
|
"kind": "variable",
|
|
55191
55245
|
"name": "ORB_STATES",
|
|
55192
55246
|
"type": {
|
|
55193
|
-
"text": "['thinking'
|
|
55247
|
+
"text": "[\n 'waiting',\n 'connecting',\n 'thinking',\n 'fetching',\n 'listening',\n 'working',\n 'done',\n]"
|
|
55194
55248
|
},
|
|
55195
|
-
"default": "['thinking', 'fetching', 'working', 'done']",
|
|
55249
|
+
"default": "[ 'waiting', 'connecting', 'thinking', 'fetching', 'listening', 'working', 'done', ]",
|
|
55196
55250
|
"description": "The states an orb can be in, in the order a task tends to pass through them.\n\nExported so the component can validate an attribute against the same list the\ngenerator reads, rather than keeping a second copy that drifts."
|
|
55197
55251
|
},
|
|
55198
55252
|
{
|
|
@@ -55201,7 +55255,7 @@
|
|
|
55201
55255
|
"type": {
|
|
55202
55256
|
"text": "Record<OrbState, OrbParams>"
|
|
55203
55257
|
},
|
|
55204
|
-
"default": "{ /* Settled: an even ball, breathing, with nothing traveling through it. */ done: { belt: 1, edge: 0, jitter: 1, rate: 1.1,
|
|
55258
|
+
"default": "{ /* The same sash as `thinking` on the same lean, thinner and calmer: the route between them is a narrowing rather than a change of shape. */ connecting: { belt: 0.32, breathe: 0.07, edge: 1, jitter: 0, orbit: 0, pulse: 0, rate: 1.05, ring: 0, rot: 1.52, shear: 0, squash: 1, waveA: 0.035, waveB: 0, }, /* Settled: an even ball, breathing, with nothing traveling through it. */ done: { belt: 1, breathe: 0.035, edge: 0, jitter: 1, orbit: 0, pulse: 0, rate: 1.1, ring: 0, rot: 0, shear: 0, squash: 1, waveA: 0, waveB: 0, }, /* A globe with a light going round it, which is the shape of looking through something. */ fetching: { belt: 1, breathe: 0, edge: 0, jitter: 0.62, orbit: 1, pulse: 0, rate: 2, ring: 0, rot: 0, shear: 0, squash: 1, waveA: 0, waveB: 0, }, /* Receptive: a closed sphere with a ripple crossing it, slower than `connecting` and symmetric where that one is a band. */ listening: { belt: 1, breathe: 0.03, edge: 0, jitter: 1, orbit: 0, pulse: 0.055, rate: 1.15, ring: 0, rot: 0, shear: 0, squash: 1, waveA: 0, waveB: 0, }, /* A narrow sash with a wave running through it, tipped so the band crosses the face rather than sitting level. */ thinking: { belt: 0.47, breathe: 0, edge: 1, jitter: 0, orbit: 0, pulse: 0, rate: 2.1, ring: 0, rot: 1.52, shear: 0, squash: 1, waveA: 0.16, waveB: 0.07, }, /* The same settled ball as `done` at a slower tempo, which is the difference between not having started and having finished. */ waiting: { belt: 1, breathe: 0.075, edge: 0, jitter: 1, orbit: 0, pulse: 0, rate: 0.55, ring: 0, rot: 0, shear: 0, squash: 1, waveA: 0, waveB: 0, }, /* **A ring, which is a different object rather than an adjusted ball.** This was a squashed sphere with its bands shearing, and a sphere adjusted is still a sphere: at 20px it read as the same mark as every other state. A torus has a hole. The bands run around the tube, so the shear twists it like rope instead of sliding flat layers past each other, and the light is what makes that turning visible at all. */ working: { belt: 1, breathe: 0.035, edge: 0, jitter: 0, orbit: 0.7, pulse: 0, rate: 1.9, ring: 1, rot: 0.3, shear: 0.62, squash: 1, waveA: 0, waveB: 0, }, }",
|
|
55205
55259
|
"description": "Each state, as numbers.\n\nThey are deliberately close together. Two states that differ in every number\ntake a long, busy route between them; these differ in the two or three that\ncarry the meaning, so a transition reads as one thing becoming another rather\nthan as a shuffle."
|
|
55206
55260
|
},
|
|
55207
55261
|
{
|
|
@@ -55234,6 +55288,75 @@
|
|
|
55234
55288
|
],
|
|
55235
55289
|
"description": "Halfway between two states, key by key."
|
|
55236
55290
|
},
|
|
55291
|
+
{
|
|
55292
|
+
"kind": "function",
|
|
55293
|
+
"name": "stateDistance",
|
|
55294
|
+
"return": {
|
|
55295
|
+
"type": {
|
|
55296
|
+
"text": "number"
|
|
55297
|
+
}
|
|
55298
|
+
},
|
|
55299
|
+
"parameters": [
|
|
55300
|
+
{
|
|
55301
|
+
"name": "a",
|
|
55302
|
+
"type": {
|
|
55303
|
+
"text": "OrbParams"
|
|
55304
|
+
}
|
|
55305
|
+
},
|
|
55306
|
+
{
|
|
55307
|
+
"name": "b",
|
|
55308
|
+
"type": {
|
|
55309
|
+
"text": "OrbParams"
|
|
55310
|
+
}
|
|
55311
|
+
}
|
|
55312
|
+
],
|
|
55313
|
+
"description": "How far apart two states are, `0` to `1`, each key against its own range.\n\nTwo states differing in one small number should not be given the time\n`thinking` to `done` needs. One length for every pair reads as rushed at one\nend of the set and slack at the other."
|
|
55314
|
+
},
|
|
55315
|
+
{
|
|
55316
|
+
"kind": "function",
|
|
55317
|
+
"name": "blendStaged",
|
|
55318
|
+
"return": {
|
|
55319
|
+
"type": {
|
|
55320
|
+
"text": "OrbParams"
|
|
55321
|
+
}
|
|
55322
|
+
},
|
|
55323
|
+
"parameters": [
|
|
55324
|
+
{
|
|
55325
|
+
"name": "a",
|
|
55326
|
+
"type": {
|
|
55327
|
+
"text": "OrbParams"
|
|
55328
|
+
}
|
|
55329
|
+
},
|
|
55330
|
+
{
|
|
55331
|
+
"name": "b",
|
|
55332
|
+
"type": {
|
|
55333
|
+
"text": "OrbParams"
|
|
55334
|
+
}
|
|
55335
|
+
},
|
|
55336
|
+
{
|
|
55337
|
+
"name": "shape",
|
|
55338
|
+
"type": {
|
|
55339
|
+
"text": "number"
|
|
55340
|
+
}
|
|
55341
|
+
},
|
|
55342
|
+
{
|
|
55343
|
+
"name": "character",
|
|
55344
|
+
"type": {
|
|
55345
|
+
"text": "number"
|
|
55346
|
+
}
|
|
55347
|
+
}
|
|
55348
|
+
],
|
|
55349
|
+
"description": "Two states blended on two clocks: the silhouette, and then what it is doing.\n\n**The other order shows a light orbiting a sash.** Every number moving on one\ncurve makes a change of state read as a cross-fade between two pictures; the\nshape arriving first makes it read as one thing becoming another."
|
|
55350
|
+
},
|
|
55351
|
+
{
|
|
55352
|
+
"kind": "variable",
|
|
55353
|
+
"name": "TRAIL",
|
|
55354
|
+
"type": {
|
|
55355
|
+
"text": "number"
|
|
55356
|
+
},
|
|
55357
|
+
"default": "0.2",
|
|
55358
|
+
"description": "How far the character trails the silhouette, as a share of the run."
|
|
55359
|
+
},
|
|
55237
55360
|
{
|
|
55238
55361
|
"kind": "function",
|
|
55239
55362
|
"name": "paramsFor",
|
|
@@ -55446,6 +55569,30 @@
|
|
|
55446
55569
|
"module": "src/orb/root/orb-shapes.ts"
|
|
55447
55570
|
}
|
|
55448
55571
|
},
|
|
55572
|
+
{
|
|
55573
|
+
"kind": "js",
|
|
55574
|
+
"name": "stateDistance",
|
|
55575
|
+
"declaration": {
|
|
55576
|
+
"name": "stateDistance",
|
|
55577
|
+
"module": "src/orb/root/orb-shapes.ts"
|
|
55578
|
+
}
|
|
55579
|
+
},
|
|
55580
|
+
{
|
|
55581
|
+
"kind": "js",
|
|
55582
|
+
"name": "blendStaged",
|
|
55583
|
+
"declaration": {
|
|
55584
|
+
"name": "blendStaged",
|
|
55585
|
+
"module": "src/orb/root/orb-shapes.ts"
|
|
55586
|
+
}
|
|
55587
|
+
},
|
|
55588
|
+
{
|
|
55589
|
+
"kind": "js",
|
|
55590
|
+
"name": "TRAIL",
|
|
55591
|
+
"declaration": {
|
|
55592
|
+
"name": "TRAIL",
|
|
55593
|
+
"module": "src/orb/root/orb-shapes.ts"
|
|
55594
|
+
}
|
|
55595
|
+
},
|
|
55449
55596
|
{
|
|
55450
55597
|
"kind": "js",
|
|
55451
55598
|
"name": "paramsFor",
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Reading a computed color the engine has resolved but not converted.
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* A computed color as three sRGB bytes, whatever space it was written in.
|
|
6
|
+
*
|
|
7
|
+
* **Painting it is the only way to read it.** A color-typed property is
|
|
8
|
+
* resolved before it is reported, but resolved is not the same as converted:
|
|
9
|
+
* Chrome hands back `lab(100 0 0)` for a token built through `oklab`, and this
|
|
10
|
+
* used to scrape the first three numbers out of that and call them red, green
|
|
11
|
+
* and blue. White arrived as `rgb(100, 0, 0)`. In light mode the near dots were
|
|
12
|
+
* `lab(0 0 0)`, which scrapes to black and looks right, so only dark mode showed
|
|
13
|
+
* it: dark red mixed toward black, on a near-black ground.
|
|
14
|
+
*
|
|
15
|
+
* A 1x1 fill and `getImageData` is a readback, so the answer is cached against
|
|
16
|
+
* the string it came from. There are two per orb and they change when the theme
|
|
17
|
+
* does.
|
|
18
|
+
*/
|
|
19
|
+
export declare const readColor: (value: string) => [number, number, number];
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
let swatch;
|
|
2
|
+
const known = new Map();
|
|
3
|
+
export const readColor = (value) => {
|
|
4
|
+
const seen = known.get(value);
|
|
5
|
+
if (seen) {
|
|
6
|
+
return seen;
|
|
7
|
+
}
|
|
8
|
+
if (swatch === undefined) {
|
|
9
|
+
swatch = document.createElement('canvas').getContext('2d', { willReadFrequently: true });
|
|
10
|
+
}
|
|
11
|
+
if (!swatch) {
|
|
12
|
+
return [128, 128, 128];
|
|
13
|
+
}
|
|
14
|
+
swatch.clearRect(0, 0, 1, 1);
|
|
15
|
+
swatch.fillStyle = '#808080';
|
|
16
|
+
swatch.fillStyle = value;
|
|
17
|
+
swatch.fillRect(0, 0, 1, 1);
|
|
18
|
+
const [red, green, blue] = swatch.getImageData(0, 0, 1, 1).data;
|
|
19
|
+
const rgb = [red ?? 128, green ?? 128, blue ?? 128];
|
|
20
|
+
if (known.size > 64) {
|
|
21
|
+
known.clear();
|
|
22
|
+
}
|
|
23
|
+
known.set(value, rgb);
|
|
24
|
+
return rgb;
|
|
25
|
+
};
|
|
@@ -5,19 +5,29 @@ import { type OrbState } from './orb-shapes.js';
|
|
|
5
5
|
* @summary Says what an agent is doing, as a shape rather than a word.
|
|
6
6
|
*
|
|
7
7
|
* @description
|
|
8
|
-
* A cloud of dots
|
|
9
|
-
* `thinking`
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
8
|
+
* A cloud of dots, drawn to a canvas, with one shape per state. `connecting`
|
|
9
|
+
* and `thinking` are the same leaning sash and differ in how agitated it is;
|
|
10
|
+
* `waiting` and `done` are the same settled ball at different tempos, which is
|
|
11
|
+
* the difference between not having started and having finished. `fetching` is
|
|
12
|
+
* a globe with a light going round it, `listening` a closed sphere with a
|
|
13
|
+
* ripple crossing it, and `working` a ring.
|
|
13
14
|
*
|
|
14
|
-
* **None of them is a separate drawing.** Each is the same banded
|
|
15
|
+
* **None of them is a separate drawing.** Each is the same banded grid given
|
|
15
16
|
* different numbers, so changing state interpolates the numbers and every frame
|
|
16
17
|
* in between is a whole shape. A loader that cuts between pictures says the
|
|
17
18
|
* work restarted; one that carries a shape into the next says it moved on.
|
|
18
19
|
*
|
|
19
|
-
* **
|
|
20
|
-
*
|
|
20
|
+
* **A change is measured before it is played.** Two states differing in one
|
|
21
|
+
* small number are given less time than a sash becoming a ring, and the
|
|
22
|
+
* silhouette leads what the shape is doing, so a light is never seen orbiting
|
|
23
|
+
* something that has not finished becoming round.
|
|
24
|
+
*
|
|
25
|
+
* **Nothing spins.** The whole cloud holds still and everything that moves is
|
|
26
|
+
* moving inside it, which is what makes it read as thought rather than as a
|
|
27
|
+
* thing being rotated. The one exception is the light, which travels because a
|
|
28
|
+
* ring of evenly spaced dots is unchanged by rotation: without something fixed
|
|
29
|
+
* in space passing over them, a state that turns has nothing a reader can see
|
|
30
|
+
* turning.
|
|
21
31
|
*
|
|
22
32
|
* **The palette is read from the tokens**, not given as colors: a dot's ink is
|
|
23
33
|
* mixed toward the ground by how far away it is, and both ends come from
|
|
@@ -91,6 +101,8 @@ export declare class HelixOrb extends HelixElement {
|
|
|
91
101
|
*/
|
|
92
102
|
private from;
|
|
93
103
|
private morphAt;
|
|
104
|
+
/** How far the current change travels, `0` to `1`. */
|
|
105
|
+
private reach;
|
|
94
106
|
/**
|
|
95
107
|
* The state's clock, accumulated rather than derived.
|
|
96
108
|
*
|
|
@@ -118,6 +130,15 @@ export declare class HelixOrb extends HelixElement {
|
|
|
118
130
|
private measure;
|
|
119
131
|
/** Begins a transition from whatever is on the screen right now. */
|
|
120
132
|
private turn;
|
|
133
|
+
/**
|
|
134
|
+
* How long this particular change is given.
|
|
135
|
+
*
|
|
136
|
+
* **Near states cross quickly and far ones are not hurried.** One length for
|
|
137
|
+
* every pair read as rushed going from `waiting` to `done`, which differ in
|
|
138
|
+
* two small numbers, and slack going from `thinking` to `working`, which is a
|
|
139
|
+
* sash becoming a ring.
|
|
140
|
+
*/
|
|
141
|
+
private get span();
|
|
121
142
|
/** How far through a transition, `1` when there is not one. */
|
|
122
143
|
private get progress();
|
|
123
144
|
private paramsNow;
|
|
@@ -135,6 +156,14 @@ export declare class HelixOrb extends HelixElement {
|
|
|
135
156
|
*/
|
|
136
157
|
private paint;
|
|
137
158
|
}
|
|
159
|
+
/**
|
|
160
|
+
* The numbers out of a resolved color.
|
|
161
|
+
*
|
|
162
|
+
* The engine reports color-typed properties as `rgb()` or `color()`, so the
|
|
163
|
+
* digits are already there to be read. Deliberately forgiving all the same: a
|
|
164
|
+
* value this cannot parse costs the orb its depth rather than its existence,
|
|
165
|
+
* and a test environment with no layout engine is exactly such a value.
|
|
166
|
+
*/
|
|
138
167
|
declare global {
|
|
139
168
|
interface HTMLElementTagNameMap {
|
|
140
169
|
'helix-orb': HelixOrb;
|
|
@@ -7,14 +7,20 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
|
|
|
7
7
|
import { customElement, HelixElement, hostAria } from '@fusion.dev/helix-core';
|
|
8
8
|
import { html } from 'lit';
|
|
9
9
|
import { property } from 'lit/decorators.js';
|
|
10
|
+
import { readColor } from './orb-color.js';
|
|
10
11
|
import { styles } from './orb-root.css.js';
|
|
11
|
-
import {
|
|
12
|
-
const
|
|
12
|
+
import { blendStaged, evenSphere, fibonacci, meshFor, ORB_STATES, orbPoint, paramsFor, project, smoother, stateDistance, TRAIL, } from './orb-shapes.js';
|
|
13
|
+
const MORPH_NEAR = 380;
|
|
14
|
+
const MORPH_REACH = 580;
|
|
15
|
+
const LIGHT_Y = 0.36;
|
|
13
16
|
const STILL_PHASE = 1.4;
|
|
14
17
|
const LABELS = {
|
|
18
|
+
connecting: 'Connecting',
|
|
15
19
|
done: 'Done',
|
|
16
20
|
fetching: 'Fetching',
|
|
21
|
+
listening: 'Listening',
|
|
17
22
|
thinking: 'Thinking',
|
|
23
|
+
waiting: 'Waiting',
|
|
18
24
|
working: 'Working',
|
|
19
25
|
};
|
|
20
26
|
let HelixOrb = class HelixOrb extends HelixElement {
|
|
@@ -29,6 +35,7 @@ let HelixOrb = class HelixOrb extends HelixElement {
|
|
|
29
35
|
this.box = 0;
|
|
30
36
|
this.from = paramsFor('thinking');
|
|
31
37
|
this.morphAt = 0;
|
|
38
|
+
this.reach = 0;
|
|
32
39
|
this.phase = STILL_PHASE;
|
|
33
40
|
this.last = 0;
|
|
34
41
|
this.tick = () => {
|
|
@@ -148,19 +155,26 @@ let HelixOrb = class HelixOrb extends HelixElement {
|
|
|
148
155
|
}
|
|
149
156
|
turn() {
|
|
150
157
|
this.from = this.paramsNow();
|
|
158
|
+
this.reach = stateDistance(this.from, paramsFor(this.state));
|
|
151
159
|
this.morphAt = performance.now();
|
|
152
160
|
if (!this.running) {
|
|
153
161
|
this.paint(0);
|
|
154
162
|
this.play();
|
|
155
163
|
}
|
|
156
164
|
}
|
|
165
|
+
get span() {
|
|
166
|
+
return MORPH_NEAR + MORPH_REACH * this.reach;
|
|
167
|
+
}
|
|
157
168
|
get progress() {
|
|
158
|
-
return this.morphAt === 0 ? 1 : Math.min(1, (performance.now() - this.morphAt) /
|
|
169
|
+
return this.morphAt === 0 ? 1 : Math.min(1, (performance.now() - this.morphAt) / this.span);
|
|
159
170
|
}
|
|
160
171
|
paramsNow() {
|
|
161
172
|
const to = paramsFor(this.state);
|
|
162
173
|
const k = this.progress;
|
|
163
|
-
|
|
174
|
+
if (k >= 1) {
|
|
175
|
+
return to;
|
|
176
|
+
}
|
|
177
|
+
return blendStaged(this.from, to, smoother(k), smoother(Math.max(0, k - TRAIL) / (1 - TRAIL)));
|
|
164
178
|
}
|
|
165
179
|
play() {
|
|
166
180
|
if (this.running || this.motion?.matches || !this.onScreen) {
|
|
@@ -188,8 +202,14 @@ let HelixOrb = class HelixOrb extends HelixElement {
|
|
|
188
202
|
const ground = readColor(painted.textDecorationColor);
|
|
189
203
|
const mesh = meshFor(size);
|
|
190
204
|
const even = evenSphere(mesh.lanes, mesh.segs);
|
|
191
|
-
const
|
|
192
|
-
const
|
|
205
|
+
const spin = this.phase * 0.9;
|
|
206
|
+
const lx = Math.cos(spin) * 0.9;
|
|
207
|
+
const lz = Math.sin(spin) * 0.9;
|
|
208
|
+
const llen = Math.hypot(lx, LIGHT_Y, lz) || 1;
|
|
209
|
+
const swell = still || this.progress >= 1
|
|
210
|
+
? 1
|
|
211
|
+
: 1 + (0.035 + 0.1 * this.reach) * Math.sin(Math.PI * this.progress ** 0.82);
|
|
212
|
+
const shell = swell * (1 + params.breathe * Math.sin(this.phase * 0.62));
|
|
193
213
|
const dots = [];
|
|
194
214
|
for (let i = 0; i < mesh.ghostCount; i++) {
|
|
195
215
|
const [x, y, z] = fibonacci(i, mesh.ghostCount);
|
|
@@ -211,7 +231,8 @@ let HelixOrb = class HelixOrb extends HelixElement {
|
|
|
211
231
|
const [x, y, z] = orbPoint(u, s / mesh.segs, this.phase, params, index, even);
|
|
212
232
|
const [px, py, pz] = project(size, x * shell, y * shell, z * shell);
|
|
213
233
|
const depth = (pz + 1) / 2;
|
|
214
|
-
const
|
|
234
|
+
const facing = (x * lx + y * LIGHT_Y + z * lz) / llen;
|
|
235
|
+
const boost = params.orbit * (facing > 0 ? facing ** 11 : 0) +
|
|
215
236
|
params.jitter * (0.1 + 0.1 * Math.sin(this.phase * 0.6));
|
|
216
237
|
dots.push({
|
|
217
238
|
alpha: mesh.aMin + (1 - mesh.aMin) * depth,
|
|
@@ -253,10 +274,3 @@ HelixOrb = __decorate([
|
|
|
253
274
|
customElement('helix-orb')
|
|
254
275
|
], HelixOrb);
|
|
255
276
|
export { HelixOrb };
|
|
256
|
-
const readColor = (value) => {
|
|
257
|
-
const parts = value.match(/-?[\d.]+/g);
|
|
258
|
-
if (!parts || parts.length < 3) {
|
|
259
|
-
return [128, 128, 128];
|
|
260
|
-
}
|
|
261
|
-
return [Number(parts[0]) || 0, Number(parts[1]) || 0, Number(parts[2]) || 0];
|
|
262
|
-
};
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* Exported so the component can validate an attribute against the same list the
|
|
5
5
|
* generator reads, rather than keeping a second copy that drifts.
|
|
6
6
|
*/
|
|
7
|
-
export declare const ORB_STATES: readonly ['thinking', 'fetching', 'working', 'done'];
|
|
7
|
+
export declare const ORB_STATES: readonly ['waiting', 'connecting', 'thinking', 'fetching', 'listening', 'working', 'done'];
|
|
8
8
|
/** What the agent is doing. */
|
|
9
9
|
export type OrbState = (typeof ORB_STATES)[number];
|
|
10
10
|
/**
|
|
@@ -28,12 +28,18 @@ export interface OrbParams {
|
|
|
28
28
|
edge: number;
|
|
29
29
|
/** How far toward an even sphere, `0` the banded grid and `1` fully relaxed. */
|
|
30
30
|
jitter: number;
|
|
31
|
+
/** How far the whole cloud swells and settles, `0` still. */
|
|
32
|
+
breathe: number;
|
|
33
|
+
/** Strength of a highlight traveling around the ball, `0` absent. */
|
|
34
|
+
orbit: number;
|
|
35
|
+
/** A ripple over the surface, applied after the sphere is closed. */
|
|
36
|
+
pulse: number;
|
|
31
37
|
/** How fast this state's own clock runs. */
|
|
32
38
|
rate: number;
|
|
39
|
+
/** How far the ball has opened into a ring, `0` a sphere and `1` a torus. */
|
|
40
|
+
ring: number;
|
|
33
41
|
/** Which way the axis leans, in radians. */
|
|
34
42
|
rot: number;
|
|
35
|
-
/** Where the sweeping highlight is, `0` absent and `1` full strength. */
|
|
36
|
-
scan: number;
|
|
37
43
|
/** How hard the bands slide past each other. */
|
|
38
44
|
shear: number;
|
|
39
45
|
/** How flattened the ball is along its axis, `1` round. */
|
|
@@ -54,6 +60,24 @@ export interface OrbParams {
|
|
|
54
60
|
export declare const ORB_PARAMS: Record<OrbState, OrbParams>;
|
|
55
61
|
/** Halfway between two states, key by key. */
|
|
56
62
|
export declare const blendParams: (a: OrbParams, b: OrbParams, k: number) => OrbParams;
|
|
63
|
+
/**
|
|
64
|
+
* How far apart two states are, `0` to `1`, each key against its own range.
|
|
65
|
+
*
|
|
66
|
+
* Two states differing in one small number should not be given the time
|
|
67
|
+
* `thinking` to `done` needs. One length for every pair reads as rushed at one
|
|
68
|
+
* end of the set and slack at the other.
|
|
69
|
+
*/
|
|
70
|
+
export declare const stateDistance: (a: OrbParams, b: OrbParams) => number;
|
|
71
|
+
/**
|
|
72
|
+
* Two states blended on two clocks: the silhouette, and then what it is doing.
|
|
73
|
+
*
|
|
74
|
+
* **The other order shows a light orbiting a sash.** Every number moving on one
|
|
75
|
+
* curve makes a change of state read as a cross-fade between two pictures; the
|
|
76
|
+
* shape arriving first makes it read as one thing becoming another.
|
|
77
|
+
*/
|
|
78
|
+
export declare const blendStaged: (a: OrbParams, b: OrbParams, shape: number, character: number) => OrbParams;
|
|
79
|
+
/** How far the character trails the silhouette, as a share of the run. */
|
|
80
|
+
export declare const TRAIL = 0.2;
|
|
57
81
|
/** The state's numbers, or `thinking`'s where the name is not one we draw. */
|
|
58
82
|
export declare const paramsFor: (state: string | undefined) => OrbParams;
|
|
59
83
|
/** Smootherstep: zero slope and zero acceleration at both ends. */
|
|
@@ -1,12 +1,38 @@
|
|
|
1
|
-
export const ORB_STATES = [
|
|
1
|
+
export const ORB_STATES = [
|
|
2
|
+
'waiting',
|
|
3
|
+
'connecting',
|
|
4
|
+
'thinking',
|
|
5
|
+
'fetching',
|
|
6
|
+
'listening',
|
|
7
|
+
'working',
|
|
8
|
+
'done',
|
|
9
|
+
];
|
|
2
10
|
export const ORB_PARAMS = {
|
|
11
|
+
connecting: {
|
|
12
|
+
belt: 0.32,
|
|
13
|
+
breathe: 0.07,
|
|
14
|
+
edge: 1,
|
|
15
|
+
jitter: 0,
|
|
16
|
+
orbit: 0,
|
|
17
|
+
pulse: 0,
|
|
18
|
+
rate: 1.05,
|
|
19
|
+
ring: 0,
|
|
20
|
+
rot: 1.52,
|
|
21
|
+
shear: 0,
|
|
22
|
+
squash: 1,
|
|
23
|
+
waveA: 0.035,
|
|
24
|
+
waveB: 0,
|
|
25
|
+
},
|
|
3
26
|
done: {
|
|
4
27
|
belt: 1,
|
|
28
|
+
breathe: 0.035,
|
|
5
29
|
edge: 0,
|
|
6
30
|
jitter: 1,
|
|
31
|
+
orbit: 0,
|
|
32
|
+
pulse: 0,
|
|
7
33
|
rate: 1.1,
|
|
34
|
+
ring: 0,
|
|
8
35
|
rot: 0,
|
|
9
|
-
scan: 0,
|
|
10
36
|
shear: 0,
|
|
11
37
|
squash: 1,
|
|
12
38
|
waveA: 0,
|
|
@@ -14,11 +40,29 @@ export const ORB_PARAMS = {
|
|
|
14
40
|
},
|
|
15
41
|
fetching: {
|
|
16
42
|
belt: 1,
|
|
43
|
+
breathe: 0,
|
|
17
44
|
edge: 0,
|
|
18
|
-
jitter: 0,
|
|
19
|
-
|
|
45
|
+
jitter: 0.62,
|
|
46
|
+
orbit: 1,
|
|
47
|
+
pulse: 0,
|
|
48
|
+
rate: 2,
|
|
49
|
+
ring: 0,
|
|
50
|
+
rot: 0,
|
|
51
|
+
shear: 0,
|
|
52
|
+
squash: 1,
|
|
53
|
+
waveA: 0,
|
|
54
|
+
waveB: 0,
|
|
55
|
+
},
|
|
56
|
+
listening: {
|
|
57
|
+
belt: 1,
|
|
58
|
+
breathe: 0.03,
|
|
59
|
+
edge: 0,
|
|
60
|
+
jitter: 1,
|
|
61
|
+
orbit: 0,
|
|
62
|
+
pulse: 0.055,
|
|
63
|
+
rate: 1.15,
|
|
64
|
+
ring: 0,
|
|
20
65
|
rot: 0,
|
|
21
|
-
scan: 1,
|
|
22
66
|
shear: 0,
|
|
23
67
|
squash: 1,
|
|
24
68
|
waveA: 0,
|
|
@@ -26,25 +70,46 @@ export const ORB_PARAMS = {
|
|
|
26
70
|
},
|
|
27
71
|
thinking: {
|
|
28
72
|
belt: 0.47,
|
|
73
|
+
breathe: 0,
|
|
29
74
|
edge: 1,
|
|
30
75
|
jitter: 0,
|
|
76
|
+
orbit: 0,
|
|
77
|
+
pulse: 0,
|
|
31
78
|
rate: 2.1,
|
|
79
|
+
ring: 0,
|
|
32
80
|
rot: 1.52,
|
|
33
|
-
scan: 0,
|
|
34
81
|
shear: 0,
|
|
35
82
|
squash: 1,
|
|
36
83
|
waveA: 0.16,
|
|
37
84
|
waveB: 0.07,
|
|
38
85
|
},
|
|
86
|
+
waiting: {
|
|
87
|
+
belt: 1,
|
|
88
|
+
breathe: 0.075,
|
|
89
|
+
edge: 0,
|
|
90
|
+
jitter: 1,
|
|
91
|
+
orbit: 0,
|
|
92
|
+
pulse: 0,
|
|
93
|
+
rate: 0.55,
|
|
94
|
+
ring: 0,
|
|
95
|
+
rot: 0,
|
|
96
|
+
shear: 0,
|
|
97
|
+
squash: 1,
|
|
98
|
+
waveA: 0,
|
|
99
|
+
waveB: 0,
|
|
100
|
+
},
|
|
39
101
|
working: {
|
|
40
102
|
belt: 1,
|
|
103
|
+
breathe: 0.035,
|
|
41
104
|
edge: 0,
|
|
42
105
|
jitter: 0,
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
106
|
+
orbit: 0.7,
|
|
107
|
+
pulse: 0,
|
|
108
|
+
rate: 1.9,
|
|
109
|
+
ring: 1,
|
|
110
|
+
rot: 0.3,
|
|
111
|
+
shear: 0.62,
|
|
112
|
+
squash: 1,
|
|
48
113
|
waveA: 0,
|
|
49
114
|
waveB: 0,
|
|
50
115
|
},
|
|
@@ -57,6 +122,51 @@ export const blendParams = (a, b, k) => {
|
|
|
57
122
|
}
|
|
58
123
|
return out;
|
|
59
124
|
};
|
|
125
|
+
const SPANS = {
|
|
126
|
+
belt: 1,
|
|
127
|
+
breathe: 0.08,
|
|
128
|
+
edge: 1,
|
|
129
|
+
jitter: 1,
|
|
130
|
+
orbit: 1,
|
|
131
|
+
pulse: 0.09,
|
|
132
|
+
rate: 2.5,
|
|
133
|
+
ring: 1,
|
|
134
|
+
rot: 1.6,
|
|
135
|
+
shear: 1.3,
|
|
136
|
+
squash: 1,
|
|
137
|
+
waveA: 0.2,
|
|
138
|
+
waveB: 0.1,
|
|
139
|
+
};
|
|
140
|
+
const STRUCTURE = [
|
|
141
|
+
'belt',
|
|
142
|
+
'edge',
|
|
143
|
+
'jitter',
|
|
144
|
+
'ring',
|
|
145
|
+
'rot',
|
|
146
|
+
'shear',
|
|
147
|
+
'squash',
|
|
148
|
+
'waveA',
|
|
149
|
+
'waveB',
|
|
150
|
+
];
|
|
151
|
+
const CHARACTER = ['breathe', 'orbit', 'pulse', 'rate'];
|
|
152
|
+
export const stateDistance = (a, b) => {
|
|
153
|
+
let sum = 0;
|
|
154
|
+
for (const key of KEYS) {
|
|
155
|
+
sum += Math.abs(b[key] - a[key]) / SPANS[key];
|
|
156
|
+
}
|
|
157
|
+
return Math.min(1, sum / 3.2);
|
|
158
|
+
};
|
|
159
|
+
export const blendStaged = (a, b, shape, character) => {
|
|
160
|
+
const out = {};
|
|
161
|
+
for (const key of STRUCTURE) {
|
|
162
|
+
out[key] = a[key] + (b[key] - a[key]) * shape;
|
|
163
|
+
}
|
|
164
|
+
for (const key of CHARACTER) {
|
|
165
|
+
out[key] = a[key] + (b[key] - a[key]) * character;
|
|
166
|
+
}
|
|
167
|
+
return out;
|
|
168
|
+
};
|
|
169
|
+
export const TRAIL = 0.2;
|
|
60
170
|
export const paramsFor = (state) => ORB_PARAMS[state] ?? ORB_PARAMS.thinking;
|
|
61
171
|
const TAU = Math.PI * 2;
|
|
62
172
|
export const smoother = (t) => t * t * t * (t * (t * 6 - 15) + 10);
|
|
@@ -92,12 +202,28 @@ export const evenSphere = (lanes, segs) => {
|
|
|
92
202
|
return out;
|
|
93
203
|
};
|
|
94
204
|
const SPAN = 1.86;
|
|
205
|
+
const RING_HOLE = 0.64;
|
|
206
|
+
const RING_TUBE = 0.36;
|
|
95
207
|
export const orbPoint = (u, v, phase, p, index, even) => {
|
|
96
208
|
const th = v * TAU + p.shear * phase * 0.55 * (u - 0.5) * 2;
|
|
97
209
|
const wave = p.waveA * Math.sin(th * 3 - phase * 1.7 + u * 3.1) + p.waveB * Math.sin(th * 5 + phase * 1.1);
|
|
98
210
|
const y = Math.max(-0.995, Math.min(0.995, (u - 0.5) * SPAN * p.belt + wave));
|
|
99
211
|
const r = Math.sqrt(Math.max(0, 1 - y * y));
|
|
100
212
|
let point = [r * Math.cos(th), y * p.squash, r * Math.sin(th)];
|
|
213
|
+
if (p.ring > 0.001) {
|
|
214
|
+
const ph = u * TAU;
|
|
215
|
+
const rr = RING_HOLE + RING_TUBE * Math.cos(ph);
|
|
216
|
+
const torus = [
|
|
217
|
+
rr * Math.cos(th),
|
|
218
|
+
RING_TUBE * Math.sin(ph),
|
|
219
|
+
rr * Math.sin(th),
|
|
220
|
+
];
|
|
221
|
+
point = [
|
|
222
|
+
point[0] + (torus[0] - point[0]) * p.ring,
|
|
223
|
+
point[1] + (torus[1] - point[1]) * p.ring,
|
|
224
|
+
point[2] + (torus[2] - point[2]) * p.ring,
|
|
225
|
+
];
|
|
226
|
+
}
|
|
101
227
|
if (p.rot) {
|
|
102
228
|
const c = Math.cos(p.rot);
|
|
103
229
|
const s = Math.sin(p.rot);
|
|
@@ -111,7 +237,12 @@ export const orbPoint = (u, v, phase, p, index, even) => {
|
|
|
111
237
|
point[2] + (e[2] - point[2]) * p.jitter,
|
|
112
238
|
];
|
|
113
239
|
const len = Math.hypot(point[0], point[1], point[2]) || 1;
|
|
114
|
-
|
|
240
|
+
const k = 1 + (1 / len - 1) * (1 - p.ring);
|
|
241
|
+
point = [point[0] * k, point[1] * k, point[2] * k];
|
|
242
|
+
}
|
|
243
|
+
if (p.pulse > 0.001) {
|
|
244
|
+
const ripple = 1 + p.pulse * Math.sin(phase * 1.5 - point[1] * 3.2);
|
|
245
|
+
point = [point[0] * ripple, point[1] * ripple, point[2] * ripple];
|
|
115
246
|
}
|
|
116
247
|
return point;
|
|
117
248
|
};
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fusion.dev/helix",
|
|
3
3
|
"description": "Styled component tier. Extends the headless tier with token-driven presentation.",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.10.1",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Ross Sheppard <ross.sheppard@fusion.dev>",
|
|
7
7
|
"repository": {
|
|
@@ -46,14 +46,14 @@
|
|
|
46
46
|
},
|
|
47
47
|
"bugs": "https://github.com/project-fusion/fusion/issues",
|
|
48
48
|
"dependencies": {
|
|
49
|
-
"@fusion.dev/helix-core": "0.
|
|
50
|
-
"@fusion.dev/helix-headless": "0.
|
|
51
|
-
"@fusion.dev/helix-styles": "0.
|
|
49
|
+
"@fusion.dev/helix-core": "0.10.1",
|
|
50
|
+
"@fusion.dev/helix-headless": "0.10.1",
|
|
51
|
+
"@fusion.dev/helix-styles": "0.10.1"
|
|
52
52
|
},
|
|
53
53
|
"devDependencies": {
|
|
54
54
|
"@custom-elements-manifest/analyzer": "^0.11.0",
|
|
55
|
-
"@fusion.dev/helix-cem": "0.
|
|
56
|
-
"@fusion.dev/helix-testing": "0.
|
|
55
|
+
"@fusion.dev/helix-cem": "0.10.1",
|
|
56
|
+
"@fusion.dev/helix-testing": "0.10.1",
|
|
57
57
|
"@fusion.dev/scripts": "0.0.0-dev",
|
|
58
58
|
"@happy-dom/global-registrator": "^20.0.0",
|
|
59
59
|
"@lit-labs/ssr": "^3.3.0",
|
package/types/jsx.d.ts
CHANGED
|
@@ -26765,19 +26765,29 @@ export type CustomElements = {
|
|
|
26765
26765
|
>;
|
|
26766
26766
|
|
|
26767
26767
|
/**
|
|
26768
|
-
* A cloud of dots
|
|
26769
|
-
* `thinking`
|
|
26770
|
-
*
|
|
26771
|
-
*
|
|
26772
|
-
*
|
|
26773
|
-
*
|
|
26774
|
-
*
|
|
26768
|
+
* A cloud of dots, drawn to a canvas, with one shape per state. `connecting`
|
|
26769
|
+
* and `thinking` are the same leaning sash and differ in how agitated it is;
|
|
26770
|
+
* `waiting` and `done` are the same settled ball at different tempos, which is
|
|
26771
|
+
* the difference between not having started and having finished. `fetching` is
|
|
26772
|
+
* a globe with a light going round it, `listening` a closed sphere with a
|
|
26773
|
+
* ripple crossing it, and `working` a ring.
|
|
26774
|
+
*
|
|
26775
|
+
* **None of them is a separate drawing.** Each is the same banded grid given
|
|
26775
26776
|
* different numbers, so changing state interpolates the numbers and every frame
|
|
26776
26777
|
* in between is a whole shape. A loader that cuts between pictures says the
|
|
26777
26778
|
* work restarted; one that carries a shape into the next says it moved on.
|
|
26778
26779
|
*
|
|
26779
|
-
* **
|
|
26780
|
-
*
|
|
26780
|
+
* **A change is measured before it is played.** Two states differing in one
|
|
26781
|
+
* small number are given less time than a sash becoming a ring, and the
|
|
26782
|
+
* silhouette leads what the shape is doing, so a light is never seen orbiting
|
|
26783
|
+
* something that has not finished becoming round.
|
|
26784
|
+
*
|
|
26785
|
+
* **Nothing spins.** The whole cloud holds still and everything that moves is
|
|
26786
|
+
* moving inside it, which is what makes it read as thought rather than as a
|
|
26787
|
+
* thing being rotated. The one exception is the light, which travels because a
|
|
26788
|
+
* ring of evenly spaced dots is unchanged by rotation: without something fixed
|
|
26789
|
+
* in space passing over them, a state that turns has nothing a reader can see
|
|
26790
|
+
* turning.
|
|
26781
26791
|
*
|
|
26782
26792
|
* **The palette is read from the tokens**, not given as colors: a dot's ink is
|
|
26783
26793
|
* mixed toward the ground by how far away it is, and both ends come from
|
|
@@ -42654,19 +42664,29 @@ export type CustomElementsSolidJs = {
|
|
|
42654
42664
|
>;
|
|
42655
42665
|
|
|
42656
42666
|
/**
|
|
42657
|
-
* A cloud of dots
|
|
42658
|
-
* `thinking`
|
|
42659
|
-
*
|
|
42660
|
-
*
|
|
42661
|
-
*
|
|
42662
|
-
*
|
|
42663
|
-
*
|
|
42667
|
+
* A cloud of dots, drawn to a canvas, with one shape per state. `connecting`
|
|
42668
|
+
* and `thinking` are the same leaning sash and differ in how agitated it is;
|
|
42669
|
+
* `waiting` and `done` are the same settled ball at different tempos, which is
|
|
42670
|
+
* the difference between not having started and having finished. `fetching` is
|
|
42671
|
+
* a globe with a light going round it, `listening` a closed sphere with a
|
|
42672
|
+
* ripple crossing it, and `working` a ring.
|
|
42673
|
+
*
|
|
42674
|
+
* **None of them is a separate drawing.** Each is the same banded grid given
|
|
42664
42675
|
* different numbers, so changing state interpolates the numbers and every frame
|
|
42665
42676
|
* in between is a whole shape. A loader that cuts between pictures says the
|
|
42666
42677
|
* work restarted; one that carries a shape into the next says it moved on.
|
|
42667
42678
|
*
|
|
42668
|
-
* **
|
|
42669
|
-
*
|
|
42679
|
+
* **A change is measured before it is played.** Two states differing in one
|
|
42680
|
+
* small number are given less time than a sash becoming a ring, and the
|
|
42681
|
+
* silhouette leads what the shape is doing, so a light is never seen orbiting
|
|
42682
|
+
* something that has not finished becoming round.
|
|
42683
|
+
*
|
|
42684
|
+
* **Nothing spins.** The whole cloud holds still and everything that moves is
|
|
42685
|
+
* moving inside it, which is what makes it read as thought rather than as a
|
|
42686
|
+
* thing being rotated. The one exception is the light, which travels because a
|
|
42687
|
+
* ring of evenly spaced dots is unchanged by rotation: without something fixed
|
|
42688
|
+
* in space passing over them, a state that turns has nothing a reader can see
|
|
42689
|
+
* turning.
|
|
42670
42690
|
*
|
|
42671
42691
|
* **The palette is read from the tokens**, not given as colors: a dot's ink is
|
|
42672
42692
|
* mixed toward the ground by how far away it is, and both ends come from
|
package/types/vue.d.ts
CHANGED
|
@@ -10542,7 +10542,7 @@ export interface WcToolkitVueGlobalComponents {
|
|
|
10542
10542
|
HelixOptionVueProps,
|
|
10543
10543
|
HelixOptionVueEvents
|
|
10544
10544
|
>;
|
|
10545
|
-
/** A cloud of dots
|
|
10545
|
+
/** A cloud of dots, drawn to a canvas, with one shape per state. 'connecting' and 'thinking' are the same leaning sash and differ in how agitated it is; 'waiting' and 'done' are the same settled ball at different tempos, which is the difference between not having started and having finished. 'fetching' is a globe with a light going round it, 'listening' a closed sphere with a ripple crossing it, and 'working' a ring. **None of them is a separate drawing.** Each is the same banded grid given different numbers, so changing state interpolates the numbers and every frame in between is a whole shape. A loader that cuts between pictures says the work restarted; one that carries a shape into the next says it moved on. **A change is measured before it is played.** Two states differing in one small number are given less time than a sash becoming a ring, and the silhouette leads what the shape is doing, so a light is never seen orbiting something that has not finished becoming round. **Nothing spins.** The whole cloud holds still and everything that moves is moving inside it, which is what makes it read as thought rather than as a thing being rotated. The one exception is the light, which travels because a ring of evenly spaced dots is unchanged by rotation: without something fixed in space passing over them, a state that turns has nothing a reader can see turning. **The palette is read from the tokens**, not given as colors: a dot's ink is mixed toward the ground by how far away it is, and both ends come from '--orb-color' and '--orb-ground'. That is what makes depth survive a theme change without the consumer restating anything. **It stops when nobody is looking**, off screen and in a background tab, and 'prefers-reduced-motion' gets one still frame rather than an empty box. */
|
|
10546
10546
|
"helix-orb": DefineCustomElement<
|
|
10547
10547
|
HelixOrb,
|
|
10548
10548
|
HelixOrbVueProps,
|