@fusion.dev/helix 0.142.1 → 0.144.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +9 -5
- package/custom-elements.json +29287 -1905
- package/dist/accordion/item/accordion-item.css.js +6 -1
- package/dist/accordion/item/accordion-item.d.ts +1 -0
- package/dist/announcement/root/announcement-root.d.ts +3 -3
- package/dist/app-header/root/app-header-root.d.ts +1 -3
- package/dist/aura/shader.d.ts +5 -1
- package/dist/aura/shader.js +88 -613
- package/dist/avatar/root/avatar-root.d.ts +3 -3
- package/dist/badge/root/badge-root.css.js +38 -2
- package/dist/badge/root/badge-root.d.ts +17 -0
- package/dist/badge/root/badge-root.js +3 -0
- package/dist/bar-chart/root/bar-chart-root.css.js +10 -0
- package/dist/blockquote/root/blockquote-root.css.js +9 -5
- package/dist/blockquote/root/blockquote-root.d.ts +5 -0
- package/dist/button/root/button-root.css.js +38 -1
- package/dist/button/root/button-root.d.ts +5 -0
- package/dist/button/root/button-root.js +2 -1
- package/dist/callout/root/callout-root.css.js +69 -11
- package/dist/callout/root/callout-root.d.ts +25 -2
- package/dist/callout/root/callout-root.js +4 -0
- package/dist/card/root/card-root.css.js +27 -1
- package/dist/card/root/card-root.d.ts +11 -0
- package/dist/carousel/root/carousel-root.js +2 -1
- package/dist/checkbox/root/checkbox-root.css.js +3 -3
- package/dist/checkbox-group/root/checkbox-group-root.d.ts +2 -0
- package/dist/checkbox-group/root/checkbox-group-root.js +2 -0
- package/dist/code-block/root/code-block-root.css.js +23 -0
- package/dist/code-block/root/code-block-root.d.ts +15 -0
- package/dist/code-block/root/code-block-root.js +8 -0
- package/dist/color-picker/root/color-picker-root.css.js +64 -0
- package/dist/color-picker/root/color-picker-root.d.ts +2 -1
- package/dist/color-picker/root/color-picker-root.js +0 -1
- package/dist/combobox/root/combobox-root.css.js +5 -4
- package/dist/copy-button/root/copy-button-root.css.js +5 -0
- package/dist/data-table/root/data-table-root.css.js +7 -0
- package/dist/date-input/root/date-input-root.css.js +19 -0
- package/dist/date-input/root/date-input-root.d.ts +8 -0
- package/dist/date-input/root/date-input-root.js +2 -0
- package/dist/date-picker/root/date-picker-root.css.js +83 -3
- package/dist/date-picker/root/date-picker-root.d.ts +1 -0
- package/dist/dialog/root/dialog-root.css.js +47 -0
- package/dist/divider/root/divider-root.css.js +8 -3
- package/dist/divider/root/divider-root.d.ts +17 -1
- package/dist/divider/root/divider-root.js +4 -0
- package/dist/donut-chart/root/donut-chart-root.css.js +10 -0
- package/dist/drawer/root/drawer-root.css.js +53 -5
- package/dist/element-events.generated.js +48 -14
- package/dist/empty/root/empty-root.css.js +9 -9
- package/dist/empty/root/empty-root.d.ts +9 -0
- package/dist/file-input/root/file-input-root.d.ts +0 -1
- package/dist/file-input/root/file-input-root.js +2 -1
- package/dist/filter-input/root/filter-input-root.d.ts +0 -1
- package/dist/filter-input/root/filter-input-root.js +2 -1
- package/dist/grid/root/grid-root.d.ts +15 -11
- package/dist/grid/root/grid-root.js +49 -15
- package/dist/heatmap/root/heatmap-root.css.js +33 -5
- package/dist/heatmap/root/heatmap-root.d.ts +4 -1
- package/dist/icon/index.d.ts +1 -0
- package/dist/icon/index.js +1 -0
- package/dist/icon/root/icon-root.d.ts +1 -1
- package/dist/icon/root/icon-root.js +1 -1
- package/dist/icon/root/index.d.ts +2 -0
- package/dist/icon/root/index.js +2 -0
- package/dist/icon-button/root/icon-button-root.css.js +80 -16
- package/dist/icon-button/root/icon-button-root.d.ts +8 -1
- package/dist/icon-button/root/icon-button-root.js +2 -1
- package/dist/image/root/image-root.css.js +1 -1
- package/dist/input/root/input-root.css.js +3 -3
- package/dist/input/root/input-root.d.ts +3 -1
- package/dist/input/root/input-root.js +0 -1
- package/dist/legend/root/legend-root.css.js +40 -13
- package/dist/legend/root/legend-root.d.ts +6 -0
- package/dist/legend/root/legend-root.js +1 -1
- package/dist/lightbox/root/lightbox-root.css.js +84 -0
- package/dist/lightbox/root/lightbox-root.d.ts +1 -0
- package/dist/line-chart/root/line-chart-root.css.js +10 -0
- package/dist/list/item/list-item.css.js +7 -1
- package/dist/loader/root/loader-root.css.js +10 -0
- package/dist/loader/root/loader-root.d.ts +10 -4
- package/dist/menu/item/menu-item.css.js +1 -1
- package/dist/menu/root/menu-root.d.ts +0 -3
- package/dist/meter/root/meter-root.css.js +27 -5
- package/dist/meter/root/meter-root.d.ts +5 -0
- package/dist/notifications/notification/notification.css.js +5 -0
- package/dist/number-input/root/number-input-root.css.js +3 -3
- package/dist/number-input/root/number-input-root.d.ts +6 -0
- package/dist/orb/root/orb-root.d.ts +11 -2
- package/dist/orb/root/orb-root.js +5 -1
- package/dist/pin-input/root/pin-input-root.css.js +12 -5
- package/dist/pin-input/root/pin-input-root.d.ts +5 -0
- package/dist/popover/root/popover-root.css.js +36 -0
- package/dist/popover/root/popover-root.d.ts +1 -0
- package/dist/progress/root/progress-root.css.js +22 -1
- package/dist/progress/root/progress-root.d.ts +5 -0
- package/dist/qr-code/root/qr-code-root.css.js +2 -1
- package/dist/qr-code/root/qr-code-root.d.ts +2 -2
- package/dist/quote/root/quote-root.css.js +1 -1
- package/dist/quote/root/quote-root.d.ts +1 -0
- package/dist/rating/root/rating-root.d.ts +3 -0
- package/dist/sandbox/index.d.ts +2 -2
- package/dist/sandbox/root/sandbox-root.d.ts +20 -1
- package/dist/sandbox/root/sandbox-root.js +27 -10
- package/dist/sandbox/source/sandbox-source.d.ts +6 -1
- package/dist/sandbox/source/sandbox-source.js +13 -3
- package/dist/sandbox/terminal/sandbox-terminal.d.ts +3 -1
- package/dist/sandbox/terminal/sandbox-terminal.js +3 -1
- package/dist/shared/chart/tooltip.css.js +25 -2
- package/dist/shared/field/field-segments.css.d.ts +1 -0
- package/dist/shared/field/field-segments.css.js +40 -0
- package/dist/skeleton/root/skeleton-root.css.js +60 -5
- package/dist/skeleton/root/skeleton-root.d.ts +21 -2
- package/dist/skeleton/root/skeleton-root.js +3 -0
- package/dist/stat/root/stat-root.css.js +7 -7
- package/dist/stat/root/stat-root.d.ts +8 -0
- package/dist/switch/root/switch-root.css.js +13 -5
- package/dist/switch/root/switch-root.d.ts +25 -1
- package/dist/switch/root/switch-root.js +7 -0
- package/dist/table/column/table-column.css.js +5 -0
- package/dist/tabs/panel/tab-panel.css.js +1 -1
- package/dist/tabs/panel/tab-panel.d.ts +2 -0
- package/dist/tabs/root/tabs-root.css.js +13 -7
- package/dist/tabs/root/tabs-root.d.ts +5 -0
- package/dist/tabs/tab/tab.css.js +4 -4
- package/dist/tabs/tab/tab.d.ts +5 -0
- package/dist/tag/group/tag-group.css.d.ts +1 -0
- package/dist/tag/group/tag-group.css.js +6 -0
- package/dist/tag/group/tag-group.d.ts +25 -0
- package/dist/tag/group/tag-group.js +16 -0
- package/dist/tag/index.d.ts +1 -0
- package/dist/tag/index.js +1 -0
- package/dist/tag/root/tag-root.css.js +50 -0
- package/dist/tag/root/tag-root.d.ts +6 -3
- package/dist/text/root/text-root.css.js +58 -1
- package/dist/text/root/text-root.d.ts +11 -2
- package/dist/text/root/text-root.js +19 -1
- package/dist/textarea/root/textarea-root.css.js +12 -4
- package/dist/textarea/root/textarea-root.d.ts +4 -0
- package/dist/time-input/root/time-input-root.css.js +19 -0
- package/dist/time-input/root/time-input-root.d.ts +8 -1
- package/dist/time-input/root/time-input-root.js +2 -1
- package/dist/toast/item/toast-item.css.js +16 -0
- package/dist/toast/root/toast-root.css.js +31 -7
- package/dist/toast/root/toast-root.d.ts +6 -9
- package/dist/toggle/group/toggle-group.css.js +16 -0
- package/dist/toggle/group/toggle-group.d.ts +3 -0
- package/dist/tour/root/tour-root.css.js +8 -0
- package/dist/tour/stop/tour-stop.css.js +37 -0
- package/dist/trend/root/trend-root.css.js +12 -5
- package/dist/trend/root/trend-root.d.ts +6 -2
- package/dist/trend/root/trend-root.js +0 -1
- package/dist/video/root/video-root.d.ts +0 -1
- package/dist/video/root/video-root.js +0 -1
- package/dist/video-playlist/menu/video-playlist-menu.d.ts +0 -1
- package/dist/video-playlist/menu/video-playlist-menu.js +0 -1
- package/lint.json +1 -1
- package/package.json +6 -6
- package/types/jsx.d.ts +9515 -2061
- package/types/svelte.d.ts +1 -0
- package/types/vue.d.ts +2302 -233
package/dist/aura/shader.js
CHANGED
|
@@ -37,29 +37,9 @@ export const FRAGMENT = `#version 300 es
|
|
|
37
37
|
uniform float uBloom;
|
|
38
38
|
uniform float uGain;
|
|
39
39
|
|
|
40
|
-
|
|
41
|
-
resting amount and 0 a set that is uniform. Read by six of the eleven
|
|
42
|
-
shapes, the ones made of many similar things, whether those are counted or
|
|
43
|
-
continuous: streaks has lanes, particles has motes, rays has a fan, aurora
|
|
44
|
-
has bundles and folds, caustics has three depths of fold and a pool over
|
|
45
|
-
them, and fracture has territories and the borders between them. The five
|
|
46
|
-
that do not read it refuse it. Braid, waves and flow have a single subject
|
|
47
|
-
and nothing to vary. Threads and lattice are even on purpose, a scatter of
|
|
48
|
-
strands and a regular structure each being what it is because its members do
|
|
49
|
-
not differ. */
|
|
40
|
+
${''}
|
|
50
41
|
uniform float uVariance;
|
|
51
|
-
|
|
52
|
-
was left to 1 when it has faded, so a spent slot costs a compare.
|
|
53
|
-
|
|
54
|
-
**This is what a fluid gets from a framebuffer, bought for eight vec3s.** A
|
|
55
|
-
real solver advects a dye texture and reads it back the next frame, which
|
|
56
|
-
needs render targets, a ping-pong pair and about six passes. What a reader
|
|
57
|
-
actually perceives from that is one thing: the cursor leaves a wake that
|
|
58
|
-
outlives it. A short history of where it went reproduces that in the single
|
|
59
|
-
pass this component already makes, at a fixed cost that does not grow with
|
|
60
|
-
how long the page has been open. What it cannot do is conserve anything, so
|
|
61
|
-
there is no diffusion and no pressure: the wake decays rather than
|
|
62
|
-
spreading. Worth knowing before this is asked to be a simulation. */
|
|
42
|
+
${''}
|
|
63
43
|
uniform vec3 uTrail[9];
|
|
64
44
|
uniform vec3 uGround;
|
|
65
45
|
uniform vec3 uHaze;
|
|
@@ -73,10 +53,7 @@ export const FRAGMENT = `#version 300 es
|
|
|
73
53
|
float noise(vec2 p) {
|
|
74
54
|
vec2 i = floor(p);
|
|
75
55
|
vec2 f = fract(p);
|
|
76
|
-
|
|
77
|
-
discontinuity at every cell edge, which four octaves of lighting turn
|
|
78
|
-
into a faint square lattice: visible on a large soft field and exactly
|
|
79
|
-
the artifact that reads as cheap. */
|
|
56
|
+
${''}
|
|
80
57
|
vec2 u = f * f * f * (f * (f * 6.0 - 15.0) + 10.0);
|
|
81
58
|
return mix(
|
|
82
59
|
mix(hash(i), hash(i + vec2(1.0, 0.0)), u.x),
|
|
@@ -85,9 +62,7 @@ export const FRAGMENT = `#version 300 es
|
|
|
85
62
|
);
|
|
86
63
|
}
|
|
87
64
|
|
|
88
|
-
|
|
89
|
-
octave on the same axes, so value noise keeps its grid however many are
|
|
90
|
-
summed. An irrational angle means no two octaves ever line up again. */
|
|
65
|
+
${''}
|
|
91
66
|
const mat2 TURN = mat2(0.8, 0.6, -0.6, 0.8);
|
|
92
67
|
|
|
93
68
|
float fbm(vec2 p) {
|
|
@@ -101,43 +76,22 @@ export const FRAGMENT = `#version 300 es
|
|
|
101
76
|
return sum;
|
|
102
77
|
}
|
|
103
78
|
|
|
104
|
-
|
|
105
|
-
This is the single largest difference between noise that reads as organic
|
|
106
|
-
and noise that reads as television static, and it costs two more fbm calls
|
|
107
|
-
rather than a different algorithm. */
|
|
79
|
+
${''}
|
|
108
80
|
float warped(vec2 p, float t) {
|
|
109
81
|
vec2 q = vec2(fbm(p + vec2(0.0, t)), fbm(p + vec2(5.2, 1.3 - t)));
|
|
110
82
|
vec2 r = vec2(fbm(p + 4.0 * q + vec2(1.7, 9.2)), fbm(p + 4.0 * q + vec2(8.3, 2.8)));
|
|
111
83
|
return fbm(p + 4.0 * r);
|
|
112
84
|
}
|
|
113
85
|
|
|
114
|
-
|
|
115
|
-
*
|
|
116
|
-
* Both abs and length have a vertex at zero and their derivative jumps
|
|
117
|
-
* across it, so a falloff built on either acquires a hard line exactly along
|
|
118
|
-
* the axis it is brightest on. That is a crease in something meant to be
|
|
119
|
-
* light, and it is what put a chevron through the braid wherever the
|
|
120
|
-
* pointer's height crossed a strand.
|
|
121
|
-
*
|
|
122
|
-
* Softening the distance rather than the exponent keeps the tails identical
|
|
123
|
-
* and rounds only the point. The softening scales with the rate, so a tight
|
|
124
|
-
* falloff is rounded tightly and a broad one broadly: at zero the result is
|
|
125
|
-
* exp(-0.06) whatever the rate is, six per cent off the peak, which is not
|
|
126
|
-
* visible as flattening.
|
|
127
|
-
*
|
|
128
|
-
* Takes the squared distance, because every caller already has one and a
|
|
129
|
-
* square root taken here is the one that would have reintroduced the vertex.
|
|
130
|
-
*/
|
|
86
|
+
${''}
|
|
131
87
|
float falloff(float d2, float k) {
|
|
132
88
|
float soft = 0.06 / k;
|
|
133
89
|
return exp(-sqrt(d2 + soft * soft) * k);
|
|
134
90
|
}
|
|
135
91
|
|
|
136
|
-
|
|
92
|
+
${''}
|
|
137
93
|
float braid(vec2 q, float t, vec2 qp, float reach) {
|
|
138
|
-
|
|
139
|
-
unmoved where it is not. A braid is a thing with a length, so what it can
|
|
140
|
-
answer with is a bend at a height, not a bulge at a point. */
|
|
94
|
+
${''}
|
|
141
95
|
float alongside = falloff((q.y - qp.y) * (q.y - qp.y), 1.1) * reach;
|
|
142
96
|
float lean = qp.x * alongside * 0.45;
|
|
143
97
|
float lit = 0.0;
|
|
@@ -147,25 +101,15 @@ export const FRAGMENT = `#version 300 es
|
|
|
147
101
|
lit += 0.8 * falloff(x * x, 13.0);
|
|
148
102
|
}
|
|
149
103
|
float volume = falloff(q.x * q.x, 2.6);
|
|
150
|
-
|
|
151
|
-
sampled square read as haze; this way they read as filaments. */
|
|
104
|
+
${''}
|
|
152
105
|
float streak = fbm(vec2(q.x * 9.0, q.y * 0.55 - t * 2.4));
|
|
153
106
|
float haze = warped(vec2(q.x * 0.8 + 4.0, q.y * 0.45), t * 0.5);
|
|
154
107
|
return lit * mix(0.35, 1.65, streak) + volume * 0.3 * mix(0.35, 1.05, haze);
|
|
155
108
|
}
|
|
156
109
|
|
|
157
|
-
|
|
110
|
+
${''}
|
|
158
111
|
float rays(vec2 q, float t, vec2 qp, float reach) {
|
|
159
|
-
|
|
160
|
-
re-aims the whole fan, which is a thing a light does and not a thing that
|
|
161
|
-
happens when something passes in front of one, so the source is fixed and
|
|
162
|
-
the pointer is a blocker.
|
|
163
|
-
|
|
164
|
-
The shadow is angular, not radial: it is the wedge of directions the
|
|
165
|
-
object covers as seen from the source, and it only exists further along
|
|
166
|
-
than the object is. A fragment nearer the source than the blocker is in
|
|
167
|
-
front of it and stays lit, which is the whole difference between an
|
|
168
|
-
occluder and a dark patch that follows the cursor. */
|
|
112
|
+
${''}
|
|
169
113
|
vec2 o = vec2(0.0, 1.45);
|
|
170
114
|
vec2 v = q - o;
|
|
171
115
|
float dist = length(v);
|
|
@@ -174,117 +118,61 @@ export const FRAGMENT = `#version 300 es
|
|
|
174
118
|
vec2 vp = qp - o;
|
|
175
119
|
float distToBlocker = length(vp);
|
|
176
120
|
float angToBlocker = atan(vp.x, -vp.y);
|
|
177
|
-
|
|
178
|
-
as a wedge that grows the further out it is carried. */
|
|
121
|
+
${''}
|
|
179
122
|
float halfAngle = 0.055 / max(distToBlocker, 0.35);
|
|
180
123
|
float across = (ang - angToBlocker) / halfAngle;
|
|
181
|
-
|
|
182
|
-
Ramping in over a fifth of a unit started the shadow below the thing
|
|
183
|
-
supposedly casting it, which reads as two objects. */
|
|
124
|
+
${''}
|
|
184
125
|
float behind = smoothstep(-0.03, 0.05, dist - distToBlocker);
|
|
185
126
|
float shadow = exp(-across * across) * behind * reach;
|
|
186
127
|
|
|
187
128
|
float fan = fbm(vec2(ang * 8.0, dist * 0.5 - t * 1.8));
|
|
188
129
|
float dust = warped(vec2(ang * 2.0, dist * 0.7), t * 0.4);
|
|
189
130
|
float spread = smoothstep(0.85, 0.05, abs(ang));
|
|
190
|
-
|
|
191
|
-
counted: how far apart its light and dark run is how much one ray differs
|
|
192
|
-
from the next. Both ends travel toward the midpoint, so a variance of 0
|
|
193
|
-
is an even wash and a variance of 1 is exactly the pair this always had. */
|
|
131
|
+
${''}
|
|
194
132
|
float rv = clamp(uVariance, 0.0, 1.0);
|
|
195
133
|
float lit = spread * mix(mix(0.85, 0.2, rv), mix(0.85, 1.5, rv), fan) *
|
|
196
134
|
mix(0.75, 1.15, dust) * falloff(dot(v, v), 0.8);
|
|
197
135
|
return lit * (1.0 - shadow * 0.82);
|
|
198
136
|
}
|
|
199
137
|
|
|
200
|
-
|
|
138
|
+
${''}
|
|
201
139
|
float aurora(vec2 q, float t, vec2 qp, float reach) {
|
|
202
|
-
|
|
203
|
-
by it. An aurora is a sheet with an amplitude, and a swell only raised
|
|
204
|
-
the whole thing locally, which is a bump in a line. Multiplying the
|
|
205
|
-
amplitude bends it instead: the folds deepen and the ridge travels
|
|
206
|
-
further, which is what an aurora does when it is disturbed. */
|
|
140
|
+
${''}
|
|
207
141
|
float agitate = falloff((q.x - qp.x) * (q.x - qp.x), 1.5) * reach;
|
|
208
142
|
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
A falloff symmetric about the ridge is a band with a wavy center line,
|
|
212
|
-
and vertical noise on a band is an equalizer. An aurora has a sharp lower
|
|
213
|
-
border where the field lines reach their lowest and light that thins
|
|
214
|
-
upward from it, so the top and the bottom cannot be the same function:
|
|
215
|
-
cut hard below, drawn long above.
|
|
216
|
-
|
|
217
|
-
Two of them, offset and at different depths, because a single sheet reads
|
|
218
|
-
as a decal and what makes the real thing look like drapery is one curtain
|
|
219
|
-
seen through another. */
|
|
143
|
+
${''}
|
|
220
144
|
float lit = 0.0;
|
|
221
145
|
for (int i = 0; i < 2; i++) {
|
|
222
146
|
float f = float(i);
|
|
223
|
-
|
|
224
|
-
puts high frequencies in the ridge, and against a hard top edge every
|
|
225
|
-
wiggle becomes a spike: the first pass came out a mountain range. What
|
|
226
|
-
an aurora has is a long undulation with a few folds in it, which is
|
|
227
|
-
what a low fundamental and one overtone give. */
|
|
147
|
+
${''}
|
|
228
148
|
float ridge =
|
|
229
149
|
((noise(vec2(q.x * (0.55 + f * 0.2) + f * 4.0, t * 0.3)) - 0.5) * 1.7 +
|
|
230
150
|
(noise(vec2(q.x * (1.3 + f * 0.4) + f * 9.0, t * 0.45)) - 0.5) * 0.55) *
|
|
231
151
|
(1.0 + agitate * 2.0) +
|
|
232
152
|
f * 0.22;
|
|
233
|
-
|
|
234
|
-
inversion is the whole difference between an aurora and a landscape.**
|
|
235
|
-
A hard edge with mass under it is a mountain silhouette: one unbroken
|
|
236
|
-
ridge line across the frame with a striped solid below it. A curtain's
|
|
237
|
-
lower border is its sharpest, brightest line, and what rises from it
|
|
238
|
-
thins and breaks into rays. */
|
|
153
|
+
${''}
|
|
239
154
|
float depth = q.y - ridge;
|
|
240
|
-
|
|
241
|
-
narrower than a pixel is an aliased line rather than an edge.
|
|
242
|
-
|
|
243
|
-
**The border's sharpness varies along it.** A line of even weight reads
|
|
244
|
-
as drawn rather than lit however it wanders. A real lower border is
|
|
245
|
-
hard where the sheet faces us and diffuse where it turns away, so the
|
|
246
|
-
crispness is drawn from the same slow noise the folds are. */
|
|
155
|
+
${''}
|
|
247
156
|
float crisp = mix(0.04, 0.3, noise(vec2(q.x * 0.8 + f * 5.0, t * 0.15)));
|
|
248
157
|
float edge = smoothstep(-crisp, crisp * 0.5, depth);
|
|
249
|
-
|
|
250
|
-
border. At 1.5 it still stood at a fifth a whole unit up, which with
|
|
251
|
-
the bundles over it painted a solid wall of stripes from the border to
|
|
252
|
-
the top of the frame. A curtain is mostly the bottom of a curtain. */
|
|
158
|
+
${''}
|
|
253
159
|
float rise = exp(-max(depth, 0.0) * (2.9 + f * 1.1));
|
|
254
|
-
|
|
255
|
-
curtain is actually made of rather than texture on a stripe. Not
|
|
256
|
-
stretched harder than this: at 0.35 a ray held one value for its whole
|
|
257
|
-
length, which is a picket fence however the bundles are shaped. */
|
|
160
|
+
${''}
|
|
258
161
|
float rays = fbm(vec2(q.x * (9.0 + f * 4.0), q.y * 0.9 - t * (2.2 + f)));
|
|
259
162
|
|
|
260
|
-
|
|
261
|
-
where the field lines end, and without it the sheet fades in from
|
|
262
|
-
nothing and reads as fog with stripes rather than as something with a
|
|
263
|
-
boundary. Wide enough to see: at k = 26 this was two pixels and might
|
|
264
|
-
as well not have been there. */
|
|
163
|
+
${''}
|
|
265
164
|
float rim = falloff(depth * depth, 7.0) * 0.45;
|
|
266
165
|
|
|
267
|
-
|
|
268
|
-
made the ridge read as a horizon: a horizon is continuous and a curtain
|
|
269
|
-
is not. Broken into lengths by a slow mask, with real gaps between
|
|
270
|
-
them, it becomes some number of curtains rather than one long one. */
|
|
166
|
+
${''}
|
|
271
167
|
float lengths = smoothstep(0.2, 0.66, noise(vec2(q.x * 1.15 + f * 13.0, t * 0.12)));
|
|
272
168
|
|
|
273
|
-
|
|
274
|
-
fence whatever else is done to it, and the floor under it lit the sheet
|
|
275
|
-
everywhere so the rays only ever read as texture on a solid band.
|
|
276
|
-
Pushing the midtones apart leaves bright bundles with real gaps
|
|
277
|
-
between them, and the low floor is what lets the gaps be gaps. */
|
|
169
|
+
${''}
|
|
278
170
|
float bundles = smoothstep(0.34, 0.86, rays);
|
|
279
171
|
|
|
280
|
-
|
|
281
|
-
on and nearly out where it faces us. A narrow range here is a band of
|
|
282
|
-
even brightness, which is the other half of what made it read flat. */
|
|
172
|
+
${''}
|
|
283
173
|
float foldNoise = noise(vec2(q.x * 1.5 + f * 7.0, t * 0.25));
|
|
284
174
|
|
|
285
|
-
|
|
286
|
-
variance about their own midpoint: at 0 an even sheet, at 1 the
|
|
287
|
-
clumping and the deep folds this was tuned to. */
|
|
175
|
+
${''}
|
|
288
176
|
float av = clamp(uVariance, 0.0, 1.0);
|
|
289
177
|
float bundled = mix(mix(0.85, 0.1, av), mix(0.85, 1.6, av), bundles);
|
|
290
178
|
float folded = mix(mix(0.775, 0.15, av), mix(0.775, 1.4, av), foldNoise);
|
|
@@ -293,130 +181,40 @@ export const FRAGMENT = `#version 300 es
|
|
|
293
181
|
return lit;
|
|
294
182
|
}
|
|
295
183
|
|
|
296
|
-
|
|
297
|
-
*
|
|
298
|
-
* The one shape here that is about motion rather than about a form. Each lane
|
|
299
|
-
* carries a trail with its own speed, length and phase, so the field reads as
|
|
300
|
-
* something passing rather than something standing.
|
|
301
|
-
*
|
|
302
|
-
* The wrap is deliberately outside the frame. A trail restarting is a pop, so
|
|
303
|
-
* the travel runs to plus and minus 1.8 while the visible field ends nearer
|
|
304
|
-
* 1.2, and the reset happens where nobody is looking.
|
|
305
|
-
*
|
|
306
|
-
* The pointer is an obstacle: lanes bow around it and slow through it, the way
|
|
307
|
-
* anything moving past a body does. Pushed outward in proportion to the offset
|
|
308
|
-
* rather than by its sign, because a sign is a discontinuity and a
|
|
309
|
-
* discontinuity in a displacement is a crease.
|
|
310
|
-
*/
|
|
184
|
+
${''}
|
|
311
185
|
float streaks(vec2 q, float t, vec2 qp, float reach) {
|
|
312
186
|
float near = falloff(dot(q - qp, q - qp), 1.6) * reach;
|
|
313
187
|
vec2 s = q + vec2((q.x - qp.x) * near * 1.1, 0.0);
|
|
314
188
|
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
Each lane draws its speed, phase and length from a hash of its index, so
|
|
318
|
-
every one of them is at a different point in its cycle. Sampled from the
|
|
319
|
-
single lane a fragment falls in, the whole strip changes state at the
|
|
320
|
-
boundary and the field acquires a hard vertical line at every lane edge:
|
|
321
|
-
measured at 23 straight edges across the frame, and at a tilt of 90 the
|
|
322
|
-
same count arrives horizontal, which is what says they belong to the
|
|
323
|
-
shape's own axes rather than to the screen.
|
|
324
|
-
|
|
325
|
-
Visiting the neighbors and weighting each by its own distance is the same
|
|
326
|
-
answer particles already uses for the same reason. The weight reaches
|
|
327
|
-
zero between centers, so nothing is left to step.
|
|
328
|
-
|
|
329
|
-
**Few lanes, and not all of them carry anything.** A streak is an event,
|
|
330
|
-
and a field of simultaneous events is a texture. A dead lane contributes
|
|
331
|
-
nothing anywhere rather than being cut off somewhere, so it costs the
|
|
332
|
-
three lane blend nothing. */
|
|
189
|
+
${''}
|
|
333
190
|
float laneF = s.x * 1.6;
|
|
334
191
|
float base = floor(laneF);
|
|
335
192
|
|
|
336
193
|
float lit = 0.0;
|
|
337
|
-
|
|
338
|
-
most 0.15 and lanes sit 0.417 apart, so one lane out carries about a
|
|
339
|
-
fiftieth and the lane that drops out of the visited set, two out, is
|
|
340
|
-
around a ten millionth. That dropped lane is where a step could appear,
|
|
341
|
-
and it is the whole reason this loop is not a single lane. */
|
|
194
|
+
${''}
|
|
342
195
|
for (int k = -1; k <= 1; k++) {
|
|
343
196
|
float id = base + float(k);
|
|
344
197
|
float within = laneF - (id + 0.5);
|
|
345
198
|
|
|
346
|
-
|
|
347
|
-
so a variance of 0 is a rank of equal streaks at one speed rather than
|
|
348
|
-
a special case. Phase is never scaled: lanes sharing a phase march in
|
|
349
|
-
lockstep, which is not a uniform population but a broken one.
|
|
350
|
-
|
|
351
|
-
Clamped, and the upper half of that is not defensive tidying. These are
|
|
352
|
-
mix() calls, so a value past 1 extrapolates rather than exaggerating:
|
|
353
|
-
at 1.6 the length term reaches zero and beyond it goes negative, which
|
|
354
|
-
makes exp(-behind / len) grow instead of decay and the lane becomes a
|
|
355
|
-
full-height white bar. Measured at 2, the frame held 93 apparent lanes
|
|
356
|
-
and six straight edges. There is nothing above 1 worth reaching, the
|
|
357
|
-
resting spread already being fourfold in speed. */
|
|
199
|
+
${''}
|
|
358
200
|
float v = clamp(uVariance, 0.0, 1.0);
|
|
359
201
|
float alive = step(0.42, hash(vec2(id, 97.0)));
|
|
360
202
|
float speed = mix(1.3, 0.55 + hash(vec2(id, 11.0)) * 1.5, v);
|
|
361
203
|
float phase = hash(vec2(id, 29.0));
|
|
362
|
-
|
|
363
|
-
is named for, and no longer: a plume that stays bright for two and a
|
|
364
|
-
half units is a searchlight, and the frame is two units tall. */
|
|
204
|
+
${''}
|
|
365
205
|
float len = mix(0.85, 0.5 + hash(vec2(id, 47.0)) * 0.8, v);
|
|
366
206
|
|
|
367
|
-
|
|
368
|
-
runs out.** With fract() over a fixed span of 3.6 a head left the top
|
|
369
|
-
at 1.8 and was moved to -1.8, taking whatever of its tail was still on
|
|
370
|
-
screen with it. That span is only off screen while the frame is small
|
|
371
|
-
enough to sit inside it, and the visible half-extent is
|
|
372
|
-
(|sin tilt| * aspect + |cos tilt|) * scale, which reaches 1.97 at a
|
|
373
|
-
tilt of 45 and 2.0 at a scale of 2. Past that the removal happens in
|
|
374
|
-
plain view, which is the popping.
|
|
375
|
-
|
|
376
|
-
Making the field periodic in y removes the event rather than moving it
|
|
377
|
-
out of sight: heads sit at every integer of u and the whole rank slides
|
|
378
|
-
through, so there is no frame in which one is created or destroyed and
|
|
379
|
-
no scale or tilt at which that becomes visible.
|
|
380
|
-
|
|
381
|
-
The gap is the distance between successive heads in a lane, and it is
|
|
382
|
-
what density is made of. It varies too: lanes alike in spacing read as
|
|
383
|
-
a grid however much else about them differs, and it has to exceed the
|
|
384
|
-
tail length, or a streak's tail reaches the next one's nose and the
|
|
385
|
-
lane reads as a dashed line rather than as separate things
|
|
386
|
-
traveling. */
|
|
207
|
+
${''}
|
|
387
208
|
float gap = mix(4.2, 3.2 + hash(vec2(id, 59.0)) * 2.2, v);
|
|
388
209
|
float travel = phase + t * speed * 1.8 / gap;
|
|
389
210
|
float u = s.y / gap - travel;
|
|
390
211
|
float w = fract(u);
|
|
391
|
-
|
|
392
|
-
Drawn separably it is a dart, and that is what these were: along the
|
|
393
|
-
lane the light stopped over a fifth of a unit, across it the lane kept
|
|
394
|
-
its full width the whole way, and the level sets of such a product meet
|
|
395
|
-
at a point. Straight edges and an apex, which is a paper dart.
|
|
396
|
-
|
|
397
|
-
So each term carries its own width. The tail leaves the head narrow and
|
|
398
|
-
spreads as it falls behind, and the front is a round cap rather than a
|
|
399
|
-
full-width wall cut off across the lane. Together that is a teardrop,
|
|
400
|
-
which is the silhouette the thing actually has. */
|
|
212
|
+
${''}
|
|
401
213
|
float across = within / 1.6;
|
|
402
|
-
|
|
403
|
-
overlapped both neighbors, so the frame came out a blue wash with no
|
|
404
|
-
streaks in it at all. Length against width is what makes a streak read
|
|
405
|
-
as a streak: at a ratio near four these were stubby rods with rounded
|
|
406
|
-
ends whichever way they tapered, and the fix for that is proportion
|
|
407
|
-
rather than another change of profile. */
|
|
214
|
+
${''}
|
|
408
215
|
float wide = mix(0.045, 0.03 + hash(vec2(id, 71.0)) * 0.04, v);
|
|
409
216
|
|
|
410
|
-
|
|
411
|
-
cap the width of the body with the body widening behind it draws a bulb
|
|
412
|
-
on a shaft; tapering the front instead draws a hairline that reads as a
|
|
413
|
-
scratch. The fault common to both is a head glow computed from the
|
|
414
|
-
distance *in front of* a head only, which never puts a round bright
|
|
415
|
-
thing at the head at all.
|
|
416
|
-
|
|
417
|
-
The glow is centered on the head, measured to whichever head is nearer
|
|
418
|
-
along the lane, so it is symmetric about the nucleus the way a coma
|
|
419
|
-
is. */
|
|
217
|
+
${''}
|
|
420
218
|
float behind = (1.0 - w) * gap;
|
|
421
219
|
float ahead = w * gap;
|
|
422
220
|
float toHead = min(ahead, behind);
|
|
@@ -426,33 +224,15 @@ export const FRAGMENT = `#version 300 es
|
|
|
426
224
|
float nucleus = exp(-near2 / (2.0 * nose * nose));
|
|
427
225
|
float coma = exp(-near2 / (2.0 * (nose * 3.0) * (nose * 3.0))) * 0.42;
|
|
428
226
|
|
|
429
|
-
|
|
430
|
-
head. A tail that holds its brightness for its whole length is a
|
|
431
|
-
streak of paint; what makes a comet read is that almost all of the
|
|
432
|
-
light is in the first tenth of it.
|
|
433
|
-
|
|
434
|
-
The onset is what keeps it continuous across a head. The plume exists
|
|
435
|
-
only behind, so its value would step from nothing to something at the
|
|
436
|
-
nucleus; ramping it in over a seventh of its own length puts that
|
|
437
|
-
transition under the brightest part of the coma, where there is nothing
|
|
438
|
-
left to see. */
|
|
227
|
+
${''}
|
|
439
228
|
float onset = 1.0 - exp(-behind / (0.15 * len));
|
|
440
229
|
|
|
441
|
-
|
|
442
|
-
min(nose * (1 + behind * 3), 0.16) saturates at a constant value of
|
|
443
|
-
behind, and a constant behind is a straight line across the lane: above
|
|
444
|
-
it the width was fixed and below it grew, and the kink between the two
|
|
445
|
-
drew a hard diagonal through the frame. A cap on a quantity that varies
|
|
446
|
-
along one axis is a cap along a line, which is the one shape this thing
|
|
447
|
-
must not have.
|
|
448
|
-
|
|
449
|
-
An exponential approach reaches the same limit without ever having a
|
|
450
|
-
corner, so there is no line to see anywhere. */
|
|
230
|
+
${''}
|
|
451
231
|
float spread = nose + (0.11 - nose) * (1.0 - exp(-behind * 1.3));
|
|
452
232
|
float tail = exp(-behind / len) * onset *
|
|
453
233
|
exp(-(across * across) / (2.0 * spread * spread)) * 0.5;
|
|
454
234
|
|
|
455
|
-
|
|
235
|
+
${''}
|
|
456
236
|
float weight = mix(1.0, 0.5 + hash(vec2(id, 83.0)) * 0.95, v);
|
|
457
237
|
lit += (nucleus + coma + tail) * alive * weight * mix(1.0, 0.45, near);
|
|
458
238
|
}
|
|
@@ -460,51 +240,18 @@ export const FRAGMENT = `#version 300 es
|
|
|
460
240
|
return lit * mix(0.55, 1.35, grain) * falloff(dot(q, q), 0.42);
|
|
461
241
|
}
|
|
462
242
|
|
|
463
|
-
|
|
464
|
-
*
|
|
465
|
-
* The softest shape here, and the only one with no filaments in it at all:
|
|
466
|
-
* where braid and threads are made of lines, this is made of gradients. The
|
|
467
|
-
* warp is what stops it sliding: bands moved by phase alone travel sideways
|
|
468
|
-
* like a barcode, and bands moved through a warped domain roll.
|
|
469
|
-
*
|
|
470
|
-
* The pointer drags them. Bowing the phase toward it bends the crests without
|
|
471
|
-
* changing how many there are, which is what a surface does when something
|
|
472
|
-
* pulls across it.
|
|
473
|
-
*/
|
|
243
|
+
${''}
|
|
474
244
|
float waves(vec2 q, float t, vec2 qp, float reach) {
|
|
475
245
|
float pull = falloff(dot(q - qp, q - qp), 1.2) * reach;
|
|
476
|
-
|
|
477
|
-
frequency of 1.7 it swung the sine's argument by about four radians,
|
|
478
|
-
which is more than a whole period: the wavefronts were destroyed rather
|
|
479
|
-
than bent and what came out was turbulence. It read as marbled paper, and
|
|
480
|
-
at a low scale it filled the frame with near white.
|
|
481
|
-
|
|
482
|
-
A tenth of that bends the fronts and leaves them fronts. */
|
|
246
|
+
${''}
|
|
483
247
|
float warp = warped(vec2(q.x * 0.5, q.y * 0.4), t * 0.3) - 0.5;
|
|
484
248
|
vec2 w = q + warp * 0.32;
|
|
485
249
|
|
|
486
|
-
|
|
487
|
-
named for.
|
|
488
|
-
|
|
489
|
-
**And the frequency has to be high enough to be a wave at all.** At 2.3
|
|
490
|
-
the period is 2.7 in shape units against a visible half height of 1, so
|
|
491
|
-
less than one crest fitted across the frame: there was nothing periodic
|
|
492
|
-
to see, and every version of this that looked like anything looked like
|
|
493
|
-
it because the warp was making clouds. Around 8 puts five crests across
|
|
494
|
-
the frame, which is a wave field rather than a single swell.
|
|
495
|
-
|
|
496
|
-
The two are deliberately not harmonic. Close but unequal frequencies beat
|
|
497
|
-
against each other, and the slow traveling interference that produces is
|
|
498
|
-
the thing worth watching. */
|
|
250
|
+
${''}
|
|
499
251
|
float a = sin((w.y * 8.1 + w.x * 2.3) - t * 0.9 - pull * 1.4);
|
|
500
252
|
float b = sin((w.y * 5.3 - w.x * 3.4) + t * 0.6 + pull * 1.0);
|
|
501
253
|
|
|
502
|
-
|
|
503
|
-
crossing at an angle give a regular grid of lobes, which came out as
|
|
504
|
-
bubble wrap and got worse the more of it fitted on screen. Waves are
|
|
505
|
-
lines. So one system carries the fronts and the other only varies their
|
|
506
|
-
brightness along their length, which is what a real swell does: the
|
|
507
|
-
crests stay crests and are taller in some places than others. */
|
|
254
|
+
${''}
|
|
508
255
|
float band = a * 0.5 + 0.5;
|
|
509
256
|
band *= mix(0.45, 1.0, b * 0.5 + 0.5);
|
|
510
257
|
|
|
@@ -512,52 +259,23 @@ export const FRAGMENT = `#version 300 es
|
|
|
512
259
|
return pow(band, 2.2) * mix(0.55, 1.2, grain) * falloff(dot(q, q), 0.4);
|
|
513
260
|
}
|
|
514
261
|
|
|
515
|
-
|
|
516
|
-
*
|
|
517
|
-
* Five curves at different frequencies and speeds, each a thin bright line
|
|
518
|
-
* rather than a band: what makes this read as woven is that they cross, and
|
|
519
|
-
* what makes it read as one object rather than five is the pinch, where every
|
|
520
|
-
* amplitude narrows at once and the whole weave gathers.
|
|
521
|
-
*
|
|
522
|
-
* The pointer is the pinch, which is the interaction this shape is for.
|
|
523
|
-
* Carrying it along drags the gathering point with it and the threads open
|
|
524
|
-
* behind and close ahead.
|
|
525
|
-
*/
|
|
262
|
+
${''}
|
|
526
263
|
float threads(vec2 q, float t, vec2 qp, float reach) {
|
|
527
264
|
float pinchAt = mix(0.0, qp.x, reach);
|
|
528
|
-
|
|
529
|
-
to a tenth and all seven threads landed on the same line, which is a
|
|
530
|
-
bright blob rather than a gathering: what a pinch has to preserve is that
|
|
531
|
-
there are still threads in it. */
|
|
265
|
+
${''}
|
|
532
266
|
float gather = 1.0 - falloff((q.x - pinchAt) * (q.x - pinchAt), 1.1) * 0.6;
|
|
533
267
|
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
What makes a weave read as a weave is that the strands are alike and only
|
|
537
|
-
their phase differs, which is also what makes it a wave rather than a
|
|
538
|
-
wobble. Given its own amplitude, height, thickness and brightness from
|
|
539
|
-
hashes, each becomes one of seven unrelated squiggles that happen to
|
|
540
|
-
share a frame.
|
|
541
|
-
|
|
542
|
-
So one amplitude, one thickness, one weight, one frequency, and the
|
|
543
|
-
phases fanned evenly across a turn. Alike, they cross at regular
|
|
544
|
-
intervals instead of at coincidences. */
|
|
268
|
+
${''}
|
|
545
269
|
float lit = 0.0;
|
|
546
270
|
for (int i = 0; i < 7; i++) {
|
|
547
271
|
float f = float(i);
|
|
548
272
|
float phase = f * (6.2831853 / 7.0);
|
|
549
273
|
|
|
550
|
-
|
|
551
|
-
amplitude: threads that only narrow still run parallel through it,
|
|
552
|
-
where threads that also converge actually gather. It closes less than
|
|
553
|
-
the amplitude does, so they draw together without stacking. */
|
|
274
|
+
${''}
|
|
554
275
|
float lane = (f - 3.0) * 0.17 * mix(1.0, gather, 0.65);
|
|
555
276
|
float amp = 0.34 * gather;
|
|
556
277
|
|
|
557
|
-
|
|
558
|
-
which bends the long run of each thread without breaking it into
|
|
559
|
-
wiggles. Low and quiet is the difference between a wave with character
|
|
560
|
-
and a wave with noise on it. */
|
|
278
|
+
${''}
|
|
561
279
|
float y =
|
|
562
280
|
lane +
|
|
563
281
|
sin(q.x * 1.5 + t * 0.55 + phase) * amp +
|
|
@@ -565,23 +283,12 @@ export const FRAGMENT = `#version 300 es
|
|
|
565
283
|
|
|
566
284
|
lit += falloff((q.y - y) * (q.y - y), 24.0);
|
|
567
285
|
}
|
|
568
|
-
|
|
569
|
-
air around them, and a wave with grain on it is a wobble again. */
|
|
286
|
+
${''}
|
|
570
287
|
float grain = fbm(vec2(q.x * 2.0, q.y * 2.0 - t));
|
|
571
288
|
return lit * mix(0.85, 1.12, grain) * falloff(dot(q, q), 0.4);
|
|
572
289
|
}
|
|
573
290
|
|
|
574
|
-
|
|
575
|
-
*
|
|
576
|
-
* One per cell of a coarse lattice, jittered off center so the lattice never
|
|
577
|
-
* shows, and drifting on its own small orbit. Nine cells are visited because a
|
|
578
|
-
* point near a boundary has to be drawn by its neighbors too, which is what
|
|
579
|
-
* stops them popping in and out at the seams.
|
|
580
|
-
*
|
|
581
|
-
* The pointer repels. Pushing along the offset rather than by its sign keeps
|
|
582
|
-
* the displacement smooth, and it is the one response here where the reader
|
|
583
|
-
* is plainly moving things rather than lighting them.
|
|
584
|
-
*/
|
|
291
|
+
${''}
|
|
585
292
|
float particles(vec2 q, float t, vec2 qp, float reach) {
|
|
586
293
|
float lit = 0.0;
|
|
587
294
|
vec2 cell = floor(q * 2.6);
|
|
@@ -602,23 +309,10 @@ export const FRAGMENT = `#version 300 es
|
|
|
602
309
|
at += away * push * 0.55;
|
|
603
310
|
|
|
604
311
|
vec2 off = q - at;
|
|
605
|
-
|
|
606
|
-
in brightness and in how fast they wandered is still made of one
|
|
607
|
-
object repeated. Nine cells are visited here, so unlike a streak lane
|
|
608
|
-
a mote may be broader as well as tighter without leaving an edge
|
|
609
|
-
anywhere. */
|
|
312
|
+
${''}
|
|
610
313
|
float grade = mix(52.0, 52.0 * (0.62 + hash(c + 5.7) * 0.95), v);
|
|
611
314
|
|
|
612
|
-
|
|
613
|
-
direction drawn per mote is not motion, it is orientation, so a field
|
|
614
|
-
of them reads as grains of rice pointing every which way rather than
|
|
615
|
-
as particles at all. Motion, if it is ever wanted here, has to come
|
|
616
|
-
from the direction each mote is actually traveling, which is the
|
|
617
|
-
wander above rather than a hash.
|
|
618
|
-
|
|
619
|
-
The halo stays. An order of magnitude wider and a tenth the strength,
|
|
620
|
-
so a mote sits in the field rather than on top of it: a hard little
|
|
621
|
-
disc on a dark ground is a pixel, and light has a neighborhood. */
|
|
315
|
+
${''}
|
|
622
316
|
float core = falloff(dot(off, off), grade);
|
|
623
317
|
float halo = falloff(dot(off, off), grade * 0.16) * 0.1;
|
|
624
318
|
lit += (core + halo) * mix(0.8, 0.35 + a * 0.9, v);
|
|
@@ -627,30 +321,7 @@ export const FRAGMENT = `#version 300 es
|
|
|
627
321
|
return lit * falloff(dot(q, q), 0.4);
|
|
628
322
|
}
|
|
629
323
|
|
|
630
|
-
|
|
631
|
-
*
|
|
632
|
-
* **The wake is one stroke, not eight marks.** A vortex per trail point,
|
|
633
|
-
* rotating the sample around its own center, draws eight discrete swirls fading
|
|
634
|
-
* in place: a row of blobs rather than anything a hand had done. The marks are
|
|
635
|
-
* a polyline. Distance is measured to the nearest *segment*, age is
|
|
636
|
-
* interpolated along it, and what a reader sees is a continuous stroke however
|
|
637
|
-
* far apart the samples fell.
|
|
638
|
-
*
|
|
639
|
-
* **And the displacement runs along the stroke, not around it.** Pushing the
|
|
640
|
-
* sample down the tangent is advection: the pattern is carried the way the
|
|
641
|
-
* hand went, which is what stirring looks like. Rotating it around a point is
|
|
642
|
-
* a whirlpool, and eight whirlpools is a washing machine.
|
|
643
|
-
*
|
|
644
|
-
* The marks arrive oldest first, so consecutive indices are consecutive in
|
|
645
|
-
* time. In the ring they are not, and a segment drawn across the wrap joined
|
|
646
|
-
* the newest mark to the oldest with a bright bar through the middle of the
|
|
647
|
-
* field.
|
|
648
|
-
*
|
|
649
|
-
* Nine, not eight: eight committed marks and the live head, which is held
|
|
650
|
-
* outside the ring so that committing appends rather than overwrites. A
|
|
651
|
-
* zero-length segment between the newest mark and the head is skipped below,
|
|
652
|
-
* which is what makes the commit invisible.
|
|
653
|
-
*/
|
|
324
|
+
${''}
|
|
654
325
|
float flowWake(vec2 at, mat2 turn, vec2 shift, out vec2 push) {
|
|
655
326
|
push = vec2(0.0);
|
|
656
327
|
float wake = 0.0;
|
|
@@ -661,11 +332,7 @@ export const FRAGMENT = `#version 300 es
|
|
|
661
332
|
if (a.z >= 1.0 || b.z >= 1.0) {
|
|
662
333
|
continue;
|
|
663
334
|
}
|
|
664
|
-
|
|
665
|
-
rotation, a scale and a parallax shift. Compared without carrying them
|
|
666
|
-
through the same three, the wake sits somewhere else entirely: at a
|
|
667
|
-
tilt of 42 and a scale of 1.7 it landed most of a frame from the
|
|
668
|
-
cursor, which is what read as offset rather than as lagging. */
|
|
335
|
+
${''}
|
|
669
336
|
vec2 pa = turn * (a.xy - shift) * uScale;
|
|
670
337
|
vec2 pb = turn * (b.xy - shift) * uScale;
|
|
671
338
|
vec2 ab = pb - pa;
|
|
@@ -676,39 +343,20 @@ export const FRAGMENT = `#version 300 es
|
|
|
676
343
|
float t = clamp(dot(at - pa, ab) / len2, 0.0, 1.0);
|
|
677
344
|
vec2 off = at - (pa + ab * t);
|
|
678
345
|
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
A circular falloff makes the wake a tube of even thickness, which is
|
|
682
|
-
what a pipe looks like and not what a stirred medium does. Ink pulled
|
|
683
|
-
through a liquid smears the way the hand went: it reaches further along
|
|
684
|
-
the direction of travel than across it. Weighting the along component
|
|
685
|
-
down stretches the ellipse into that direction, and costs one dot
|
|
686
|
-
product. */
|
|
346
|
+
${''}
|
|
687
347
|
vec2 tangent = ab * inversesqrt(len2);
|
|
688
348
|
float alongOff = dot(off, tangent);
|
|
689
349
|
float acrossOff = dot(off, vec2(-tangent.y, tangent.x));
|
|
690
350
|
float shaped = acrossOff * acrossOff + alongOff * alongOff * 0.3;
|
|
691
351
|
|
|
692
|
-
|
|
352
|
+
${''}
|
|
693
353
|
float life = 1.0 - mix(a.z, b.z, t);
|
|
694
354
|
float w = life * life * falloff(shaped, 3.2);
|
|
695
355
|
wake += w;
|
|
696
356
|
push += (ab * inversesqrt(len2)) * w;
|
|
697
357
|
}
|
|
698
358
|
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
Where the map from sample to displaced sample stops being one to one,
|
|
702
|
-
neighboring samples land on the same value and the pattern piles into a
|
|
703
|
-
hard bright line: a caustic, which is what a sharp diagonal with a bright
|
|
704
|
-
wedge beside it always is. The sum runs over eight segments of unit
|
|
705
|
-
tangents, so near the stroke it reached several times the width of the
|
|
706
|
-
falloff it was displacing across, and folded every time.
|
|
707
|
-
|
|
708
|
-
The falloff is about a third of a unit wide, so the displacement has to
|
|
709
|
-
stay under that for the map to stay monotone. Saturating rather than
|
|
710
|
-
clamped: a clamp is a corner, and a corner in a displacement is the same
|
|
711
|
-
crease by another route. */
|
|
359
|
+
${''}
|
|
712
360
|
float mag = length(push);
|
|
713
361
|
push = mag > 0.0 ? push * (0.24 / (0.9 + mag)) : vec2(0.0);
|
|
714
362
|
return wake;
|
|
@@ -717,88 +365,29 @@ export const FRAGMENT = `#version 300 es
|
|
|
717
365
|
float flow(vec2 q, float t, mat2 turn, vec2 shift) {
|
|
718
366
|
vec2 push;
|
|
719
367
|
float wake = flowWake(q, turn, shift, push);
|
|
720
|
-
|
|
368
|
+
${''}
|
|
721
369
|
vec2 p = q + push;
|
|
722
370
|
|
|
723
|
-
|
|
724
|
-
its folded look: each sample is displaced by the field's own value, so
|
|
725
|
-
structure gathers into sheets rather than staying a cloud.
|
|
726
|
-
|
|
727
|
-
Big shapes first, detail on top of them. At twice these frequencies every
|
|
728
|
-
octave landed small enough that the frame filled edge to edge with fine
|
|
729
|
-
crumple at one density: marbled stone, and it looked the same at every
|
|
730
|
-
scale, gain and bloom because there was no large form for any of them to
|
|
731
|
-
act on.
|
|
732
|
-
|
|
733
|
-
Isotropic noise cannot make a current, so anything wanting one has to
|
|
734
|
-
carry a direction, and that is a bigger change than this shape wants. */
|
|
371
|
+
${''}
|
|
735
372
|
float ink = warped(p * 0.55, t * 0.55);
|
|
736
373
|
float sheet = warped(p * 1.1 + vec2(3.1, 1.7), t * 0.35);
|
|
737
374
|
|
|
738
|
-
|
|
739
|
-
field can reach is a quarter lit, so every fragment lands in the same
|
|
740
|
-
middle band and there is no structure to look at.
|
|
741
|
-
|
|
742
|
-
And a slow large mass over the top, thresholded rather than merely
|
|
743
|
-
varied: a gentle modulation over a field that is lit everywhere is still
|
|
744
|
-
lit everywhere, and what a liquid needs is somewhere it simply is not.
|
|
745
|
-
The empty parts of the frame are what give the full parts a shape. */
|
|
375
|
+
${''}
|
|
746
376
|
float mass = smoothstep(0.24, 0.72, noise(vec2(p.x * 0.45 - t * 0.1, p.y * 0.4 + t * 0.07)));
|
|
747
|
-
|
|
748
|
-
less across the frame than the frame is wide, so a reader can sit inside
|
|
749
|
-
one void and see almost nothing: measured at scale 0.5, which came out
|
|
750
|
-
near black. Empty has to mean faint, not absent, or the shape can
|
|
751
|
-
disappear entirely at a setting the property explicitly allows. */
|
|
377
|
+
${''}
|
|
752
378
|
float body = mix(0.05, 1.4, ink) * mix(0.4, 1.2, sheet) * mix(0.22, 1.45, mass);
|
|
753
379
|
|
|
754
|
-
|
|
755
|
-
move the pointer, and a shape that is dark until touched is a shape most
|
|
756
|
-
people never see. With the voids in, halving an untouched field takes it
|
|
757
|
-
to a dim murk that reads as wet rock, so the wake lifts from a resting
|
|
758
|
-
level that is already worth looking at. */
|
|
380
|
+
${''}
|
|
759
381
|
return body * (0.85 + clamp(wake, 0.0, 1.0) * 0.5) * falloff(dot(q, q), 0.55);
|
|
760
382
|
}
|
|
761
383
|
|
|
762
|
-
|
|
763
|
-
*
|
|
764
|
-
* **A caustic is where a wavefront folds, not where it is bright.** Sampling
|
|
765
|
-
* a noise field and lighting the high parts gives clouds; what makes the
|
|
766
|
-
* pattern on a pool floor is that the surface bends light and neighboring
|
|
767
|
-
* rays land on the same spot. The cheap stand-in for that is the *zero* of a
|
|
768
|
-
* displaced wave sum rather than its peak: 1 - |sum| is thin and bright
|
|
769
|
-
* exactly where the sum crosses, which is the fold.
|
|
770
|
-
*
|
|
771
|
-
* abs() puts a derivative discontinuity along each of those lines, and here
|
|
772
|
-
* that is the drawing rather than a fault: a caustic edge is genuinely sharp,
|
|
773
|
-
* which is the whole reason it reads as light rather than as fog.
|
|
774
|
-
*/
|
|
384
|
+
${''}
|
|
775
385
|
float caustics(vec2 q, float t, vec2 qp, float reach) {
|
|
776
|
-
|
|
777
|
-
of extra phase, so the web tightens around it rather than brightening. */
|
|
386
|
+
${''}
|
|
778
387
|
float dropD = length(q - qp);
|
|
779
388
|
float drop = falloff(dropD * dropD, 1.4) * reach;
|
|
780
389
|
|
|
781
|
-
|
|
782
|
-
bright. Three depths of fold, each at its own frequency and carrying its
|
|
783
|
-
own weight in the sum, are three sizes of the same thing, and the slow
|
|
784
|
-
depth over the top is how far the lit part of the pool is from the dark
|
|
785
|
-
part. Each travels toward the middle of its own spread, so a variance of
|
|
786
|
-
0 is one scale of web lit evenly from edge to edge and a variance of 1 is
|
|
787
|
-
exactly the water this was tuned to.
|
|
788
|
-
|
|
789
|
-
The total weight is the same at either end, three layers of 0.78 being
|
|
790
|
-
the 1.0, 0.78 and 0.56 they spread into, so evening them out does not
|
|
791
|
-
also dim the frame.
|
|
792
|
-
|
|
793
|
-
The grain is left out of it. It is the texture on the light rather than a
|
|
794
|
-
member of anything, which is the same reason threads keeps its.
|
|
795
|
-
|
|
796
|
-
Clamped, and the upper half of that is not tidying: these are mix()
|
|
797
|
-
calls, so a value past 1 extrapolates rather than exaggerating. The near
|
|
798
|
-
layer's frequency runs 2.05 - 0.55v and the far layer's weight 0.78 -
|
|
799
|
-
0.22v, so at 2 the near web is drawn at 0.95, under half the scale it was
|
|
800
|
-
tuned at, and past 3.5 the far layer's weight crosses zero and that layer
|
|
801
|
-
lights everything the folds are not. */
|
|
390
|
+
${''}
|
|
802
391
|
float cv = clamp(uVariance, 0.0, 1.0);
|
|
803
392
|
|
|
804
393
|
float lit = 0.0;
|
|
@@ -806,8 +395,7 @@ export const FRAGMENT = `#version 300 es
|
|
|
806
395
|
float f = float(i);
|
|
807
396
|
vec2 p = q * mix(2.05, 1.5 + f * 0.55, cv);
|
|
808
397
|
|
|
809
|
-
|
|
810
|
-
surface does rather than sliding as a rigid pattern. */
|
|
398
|
+
${''}
|
|
811
399
|
vec2 w = p + vec2(
|
|
812
400
|
noise(p * 1.25 + vec2(t * 0.42 + f * 4.0, 0.0)),
|
|
813
401
|
noise(p * 1.1 - vec2(0.0, t * 0.36 + f * 7.0))
|
|
@@ -818,49 +406,23 @@ export const FRAGMENT = `#version 300 es
|
|
|
818
406
|
lit += pow(fold, 7.0) * mix(0.78, 1.0 - f * 0.22, cv);
|
|
819
407
|
}
|
|
820
408
|
|
|
821
|
-
|
|
822
|
-
density fill the frame edge to edge and every version of it looks the
|
|
823
|
-
same: bright everywhere carries the same amount of information as dark
|
|
824
|
-
everywhere. A slow depth over the top decides where the light is getting
|
|
825
|
-
through, so the web has somewhere to be faint and the eye somewhere to
|
|
826
|
-
start. */
|
|
409
|
+
${''}
|
|
827
410
|
float pool = smoothstep(0.2, 0.78, noise(vec2(q.x * 0.55 - t * 0.09, q.y * 0.5 + t * 0.06)));
|
|
828
411
|
|
|
829
|
-
|
|
830
|
-
only evidence of a pointer is a phase shift nobody can see. */
|
|
412
|
+
${''}
|
|
831
413
|
float dim = warped(q * 0.7, t * 0.2);
|
|
832
414
|
return lit * mix(0.55, 1.25, dim) *
|
|
833
415
|
mix(mix(0.75, 0.25, cv), mix(0.75, 1.25, cv), pool) *
|
|
834
416
|
(1.0 + drop * 0.9) * falloff(dot(q, q), 0.4);
|
|
835
417
|
}
|
|
836
418
|
|
|
837
|
-
|
|
838
|
-
*
|
|
839
|
-
* **The one shape here that is not weather.** Everything else in this set is
|
|
840
|
-
* a fluid, a light or a sky, and a design system is none of those: it is a
|
|
841
|
-
* structure, regular, with the interesting part at the joints. So this is
|
|
842
|
-
* drawn rather than simulated, and it is the only one with straight lines in
|
|
843
|
-
* it on purpose.
|
|
844
|
-
*
|
|
845
|
-
* Perspective is a divide, not a matrix. Scaling the grid by 1 / (1 + depth)
|
|
846
|
-
* makes the cells shrink with distance and the whole thing recede, which is
|
|
847
|
-
* the entire trick and costs one division.
|
|
848
|
-
*/
|
|
419
|
+
${''}
|
|
849
420
|
float lattice(vec2 q, float t, vec2 qp, float reach) {
|
|
850
|
-
|
|
851
|
-
reader is looking. A structure answers by changing its spacing, which is
|
|
852
|
-
the only thing about a lattice that can move without breaking it. */
|
|
421
|
+
${''}
|
|
853
422
|
vec2 away = q - qp;
|
|
854
423
|
float near = falloff(dot(away, away), 1.8) * reach;
|
|
855
424
|
|
|
856
|
-
|
|
857
|
-
floors meeting along y = 0, which reads as a bowtie with a crease down
|
|
858
|
-
the middle rather than as anything receding. Dividing by the distance
|
|
859
|
-
below a horizon is the actual projection: one plane, cells shrinking as
|
|
860
|
-
they approach it, and nothing above it to fold back.
|
|
861
|
-
|
|
862
|
-
It travels as well, so the structure arrives rather than sitting still.
|
|
863
|
-
Perspective and motion together are what say the plane is a plane. */
|
|
425
|
+
${''}
|
|
864
426
|
float below = max(1.45 - q.y, 0.14);
|
|
865
427
|
float depth = 1.0 / below;
|
|
866
428
|
vec2 g = vec2(
|
|
@@ -869,61 +431,23 @@ export const FRAGMENT = `#version 300 es
|
|
|
869
431
|
);
|
|
870
432
|
vec2 cell = fract(g) - 0.5;
|
|
871
433
|
|
|
872
|
-
|
|
873
|
-
into a solid sheet at the horizon. */
|
|
434
|
+
${''}
|
|
874
435
|
float rail = min(abs(cell.x), abs(cell.y));
|
|
875
436
|
float lines = falloff(rail * rail, 24.0);
|
|
876
437
|
|
|
877
|
-
|
|
878
|
-
than the rails between them: a grid of even weight is graph paper. */
|
|
438
|
+
${''}
|
|
879
439
|
float node = falloff(dot(cell, cell), 26.0) * 2.1 * (0.6 + near * 0.9);
|
|
880
440
|
|
|
881
|
-
|
|
882
|
-
where they are smallest. */
|
|
441
|
+
${''}
|
|
883
442
|
float far = smoothstep(0.0, 0.55, below) * smoothstep(3.4, 1.3, below);
|
|
884
443
|
|
|
885
444
|
float dust = warped(q * 0.9, t * 0.25);
|
|
886
445
|
return (lines * 0.5 + node) * far * mix(0.7, 1.2, dust) * falloff(dot(q, q), 0.42);
|
|
887
446
|
}
|
|
888
447
|
|
|
889
|
-
|
|
890
|
-
*
|
|
891
|
-
* **Provenance as a picture.** A Voronoi field is a set of territories, each
|
|
892
|
-
* one everything nearer to its own point than to any other, and the drawing
|
|
893
|
-
* is not the cells but the boundaries: where two claims meet is exactly
|
|
894
|
-
* what Trace is about. Nothing here is lit except the disagreements.
|
|
895
|
-
*
|
|
896
|
-
* The wall is the second nearest distance minus the nearest, which is zero
|
|
897
|
-
* on the boundary and grows into the interior. It is a genuine distance, so
|
|
898
|
-
* it needs no epsilon and produces no crease.
|
|
899
|
-
*/
|
|
448
|
+
${''}
|
|
900
449
|
float fracture(vec2 q, float t, vec2 qp, float reach) {
|
|
901
|
-
|
|
902
|
-
own cell center is the whole of what makes one differ from the next: the
|
|
903
|
-
rates are already shared, so the spread is the amplitude and nothing
|
|
904
|
-
else. At 0 every site sits at its center and every claim is the same
|
|
905
|
-
size, which draws the lattice this is a Voronoi of: a grid. That is the
|
|
906
|
-
answer rather than a collision with the shape above, which is a structure
|
|
907
|
-
in perspective lit at its joints where this is a set of claims that
|
|
908
|
-
happen to be equal.
|
|
909
|
-
|
|
910
|
-
**The alternative is a shared phase, and it is the wrong uniform.**
|
|
911
|
-
Keeping the swing and collapsing a and b would leave every site on the
|
|
912
|
-
same orbit, which is not a set of equal territories but one territory
|
|
913
|
-
repeated and the whole field sliding rigidly under it. The lanes in
|
|
914
|
-
streaks say the same thing about a phase from the other side.
|
|
915
|
-
|
|
916
|
-
At 0 the seams hold still, which is what a set of equal claims looks
|
|
917
|
-
like and not a shape that has stopped: the grain still travels over them
|
|
918
|
-
and the pointer still shoves the sites near it apart, so the one thing
|
|
919
|
-
that moves a territory is something arriving.
|
|
920
|
-
|
|
921
|
-
Clamped for the usual reason, that these are interpolations, and here
|
|
922
|
-
there is a hard edge as well as an ugly one. Nine cells are visited, so
|
|
923
|
-
the two nearest sites have to be inside them: the swing reaches
|
|
924
|
-
0.42 * v * sqrt(2) of a cell at its corner, which passes a whole cell at
|
|
925
|
-
v = 1.68, and past that a site can be nearer than anything the loop
|
|
926
|
-
looked at and the seam snaps along the lattice it was drawn to hide. */
|
|
450
|
+
${''}
|
|
927
451
|
float fv = clamp(uVariance, 0.0, 1.0);
|
|
928
452
|
|
|
929
453
|
vec2 g = q * 2.1;
|
|
@@ -937,14 +461,12 @@ export const FRAGMENT = `#version 300 es
|
|
|
937
461
|
vec2 o = vec2(float(i), float(j));
|
|
938
462
|
vec2 id = base + o;
|
|
939
463
|
|
|
940
|
-
|
|
941
|
-
than the whole field sliding. */
|
|
464
|
+
${''}
|
|
942
465
|
float a = hash(id) * 6.2831853;
|
|
943
466
|
float b = hash(id + 41.7) * 6.2831853;
|
|
944
467
|
vec2 site = o + 0.5 + 0.42 * fv * vec2(sin(t * 0.5 + a), cos(t * 0.42 + b));
|
|
945
468
|
|
|
946
|
-
|
|
947
|
-
cells there: a territory answers by giving ground. */
|
|
469
|
+
${''}
|
|
948
470
|
vec2 world = (id + 0.5) / 2.1;
|
|
949
471
|
vec2 shove = world - qp;
|
|
950
472
|
site += normalize(shove + 0.0001) * falloff(dot(shove, shove), 2.4) * reach * 0.5;
|
|
@@ -962,17 +484,7 @@ export const FRAGMENT = `#version 300 es
|
|
|
962
484
|
float wall = second - first;
|
|
963
485
|
float seam = falloff(wall * wall, 17.0);
|
|
964
486
|
|
|
965
|
-
|
|
966
|
-
mosaic of equal cells, which is a texture; what makes a set of
|
|
967
|
-
territories read is that some borders are contested and most are not. A
|
|
968
|
-
slow field decides which, and the dark stretches give the lit ones a
|
|
969
|
-
shape.
|
|
970
|
-
|
|
971
|
-
Which is the second thing variance answers for here, from the other
|
|
972
|
-
direction: how far apart the contested borders and the quiet ones are
|
|
973
|
-
lit. Both ends travel toward the midpoint, so a variance of 0 is that
|
|
974
|
-
mosaic, every border at one brightness, and the paragraph above is a
|
|
975
|
-
description of what asking for no variance gets rather than a fault. */
|
|
487
|
+
${''}
|
|
976
488
|
float contested = smoothstep(0.24, 0.8, noise(vec2(q.x * 0.6 + t * 0.07, q.y * 0.55 - t * 0.05)));
|
|
977
489
|
|
|
978
490
|
float grain = warped(q * 1.3, t * 0.3);
|
|
@@ -981,50 +493,27 @@ export const FRAGMENT = `#version 300 es
|
|
|
981
493
|
falloff(dot(q, q), 0.42);
|
|
982
494
|
}
|
|
983
495
|
|
|
984
|
-
|
|
496
|
+
${''}
|
|
985
497
|
void main() {
|
|
986
498
|
vec2 p = uv * 2.0 - 1.0;
|
|
987
499
|
float aspect = uResolution.x / max(uResolution.y, 1.0);
|
|
988
500
|
p.x *= aspect;
|
|
989
501
|
|
|
990
|
-
|
|
991
|
-
promise about what the pointer does, and translating the whole field is
|
|
992
|
-
not any of them: a consumer asking for a light asked for a light, not for
|
|
993
|
-
a light and a lean. Small is not the test.
|
|
994
|
-
|
|
995
|
-
What answers the pointer is each shape, in the terms it is made of, and
|
|
996
|
-
the three generics for a consumer who asks for one. */
|
|
502
|
+
${''}
|
|
997
503
|
vec2 q = p;
|
|
998
504
|
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
p.x is stretched by the aspect before anything is rotated, so a
|
|
1002
|
-
rotation applied here is a rotation in an anisotropic space, which is a
|
|
1003
|
-
shear. Working it through: a feature along the shape's own x axis sits
|
|
1004
|
-
where q.y = 0, which is p.y = -tan(a) * p.x, and since p.x is aspect
|
|
1005
|
-
times the screen's x the slope a reader sees is aspect * tan(a). At a
|
|
1006
|
-
widescreen 1.78 a tilt of 14 drew at 23.9 degrees, and the same number
|
|
1007
|
-
drew differently in every box the component was put in.
|
|
1008
|
-
|
|
1009
|
-
Solving aspect * tan(a) = tan(tilt) gives the angle to rotate by. The two
|
|
1010
|
-
argument atan is what makes 90 work: tan blows up there, while
|
|
1011
|
-
atan(1, 0) is exactly a quarter turn. */
|
|
505
|
+
${''}
|
|
1012
506
|
float want = radians(uTilt);
|
|
1013
507
|
float a = atan(sin(want), cos(want) * aspect);
|
|
1014
508
|
mat2 turn = mat2(cos(a), sin(a), -sin(a), cos(a));
|
|
1015
509
|
q = turn * q * uScale;
|
|
1016
510
|
|
|
1017
|
-
|
|
1018
|
-
one can answer it in its own terms. */
|
|
511
|
+
${''}
|
|
1019
512
|
vec2 qp = turn * uPointer * uScale;
|
|
1020
513
|
|
|
1021
514
|
float t = uTime * 0.06;
|
|
1022
515
|
|
|
1023
|
-
|
|
1024
|
-
Given a generic response, its own is switched off rather than layered
|
|
1025
|
-
under: two answers to one gesture is how a shared zoom and a shared glow
|
|
1026
|
-
got here in the first place, applied identically to every shape and
|
|
1027
|
-
saying nothing about any of them. */
|
|
516
|
+
${''}
|
|
1028
517
|
float own = uInteraction == 0 ? uReach : 0.0;
|
|
1029
518
|
|
|
1030
519
|
float d = 0.0;
|
|
@@ -1052,20 +541,10 @@ export const FRAGMENT = `#version 300 es
|
|
|
1052
541
|
d = fracture(q, t, qp, own);
|
|
1053
542
|
}
|
|
1054
543
|
|
|
1055
|
-
|
|
1056
|
-
Every shape is a density that falls off, so a power tightens or spreads
|
|
1057
|
-
that falloff and one control means the same thing in all of them. */
|
|
544
|
+
${''}
|
|
1058
545
|
d = pow(max(d, 0.0), mix(2.0, 0.5, clamp(uBloom, 0.0, 1.0))) * uGain;
|
|
1059
546
|
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
All three are functions of distance from the pointer and nothing else,
|
|
1063
|
-
which is exactly what makes them generic and exactly what makes them say
|
|
1064
|
-
less. The light option lifts what is lit and puts a floor under itself so
|
|
1065
|
-
there is something at the cursor over a dark field. The shadow option is
|
|
1066
|
-
that gesture inverted, which suits a bright field where a lamp would be
|
|
1067
|
-
invisible. The ripple option is the one with a clock in it, so it keeps
|
|
1068
|
-
moving after the pointer has stopped. */
|
|
547
|
+
${''}
|
|
1069
548
|
if (uInteraction != 0 && uInteraction != 4) {
|
|
1070
549
|
vec2 toCursor = p - uPointer;
|
|
1071
550
|
float near = falloff(dot(toCursor, toCursor), 3.0) * uReach;
|
|
@@ -1081,18 +560,14 @@ export const FRAGMENT = `#version 300 es
|
|
|
1081
560
|
|
|
1082
561
|
d *= mix(0.65, 1.35, smoothstep(-1.0, 1.0, q.y));
|
|
1083
562
|
|
|
1084
|
-
|
|
1085
|
-
plateau of one value, which is what makes a bright shader look like a
|
|
1086
|
-
sticker; this compresses toward one and keeps the gradient inside it. */
|
|
563
|
+
${''}
|
|
1087
564
|
float lift = 1.0 - exp(-max(d, 0.0) * 1.15);
|
|
1088
565
|
|
|
1089
566
|
vec3 rgb = mix(uGround, uHaze, smoothstep(0.0, 0.16, lift));
|
|
1090
567
|
rgb = mix(rgb, uGlow, smoothstep(0.10, 0.46, lift));
|
|
1091
568
|
rgb = mix(rgb, uPeak, smoothstep(0.40, 0.72, lift) * 0.6);
|
|
1092
569
|
|
|
1093
|
-
|
|
1094
|
-
hundred 8-bit steps across a screen, and without a sub-step of noise it
|
|
1095
|
-
paints as visible rings. */
|
|
570
|
+
${''}
|
|
1096
571
|
float dither = (hash(gl_FragCoord.xy) - 0.5) / 255.0;
|
|
1097
572
|
color = vec4(rgb + dither, 1.0);
|
|
1098
573
|
}
|