instantshader 0.4.0 → 0.5.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 +48 -1
- package/dist/index.d.ts +13 -1
- package/dist/index.js +748 -8
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
|
+

|
|
2
|
+
|
|
1
3
|
# instantshader
|
|
2
4
|
|
|
3
5
|
Animated WebGL gradient shaders with zero dependencies. Mount a live, resizable
|
|
4
6
|
gradient into any DOM element, or render a single frame to a detached canvas
|
|
5
|
-
for export pipelines. Built by [InstantGradient](https://instantgradient.com/
|
|
7
|
+
for export pipelines. Built by [InstantGradient](https://instantgradient.com/app).
|
|
6
8
|
|
|
7
9
|
## Install
|
|
8
10
|
|
|
@@ -23,6 +25,43 @@ const handle = mountGradient(document.getElementById("bg")!, {
|
|
|
23
25
|
// handle.pause() / handle.resume() / handle.dispose() when done
|
|
24
26
|
```
|
|
25
27
|
|
|
28
|
+
## Shaders
|
|
29
|
+
|
|
30
|
+
Each shader is a separate named export, so the ones you don't import
|
|
31
|
+
tree-shake away.
|
|
32
|
+
|
|
33
|
+
| Shader | Look | Params |
|
|
34
|
+
| --- | --- | --- |
|
|
35
|
+
| `flow` | Isotropic swirling currents. A curl-noise field advects the sample point before it hits fbm, so colour masses travel in continuous, fluid-like eddies with defined luminous edges and generous calm negative space. | `scale`, `curl`, `drift`, `openness`, `grain` |
|
|
36
|
+
| `beam` | One wide beam of soft light crossing a near-black frame. The palette walks the beam's length, thin brighter filaments crawl inside it, and most of the frame is dark negative space. | `scale`, `width`, `glow`, `angle`, `grain` |
|
|
37
|
+
| `bloom` | A fan of huge, ultra-soft petals radiating from the frame's bottom edge. One analytic rose-curve field, so the palette reads as concentric scalloped bands from a hot core out to a dark background, with thin dark creases between the petals. | `scale`, `petals`, `pinch`, `bend`, `sway`, `colorflow`, `grain` |
|
|
38
|
+
| `halo` | An eclipse: one dark disc with a razor-bright limb and a corona of streamers flowing outward, the palette wrapped around the ring. `x` / `y` place the disc; the default sinks it below the frame for a glowing horizon arc. | `radius`, `x`, `y`, `glow`, `crescent`, `flares`, `grain` |
|
|
39
|
+
| `strata` | Stacked cut-paper sheets, one per palette step, each casting a soft shadow on the one below. `ridges` and `stretch` reshape the relief itself, from round islands to branching spines to long agate bands. | `scale`, `layers`, `warp`, `ridges`, `stretch`, `depth`, `blend`, `angle`, `grain` |
|
|
40
|
+
| `dune` | Overlapping crests rolling across the frame, back to front. Each has one crisp top edge and airbrushes away below it; neighbouring crests slide against each other. | `layers`, `swell`, `waves`, `fade`, `soft`, `angle`, `grain` |
|
|
41
|
+
| `whorl` | A logarithmic spiral of curved blades, each with one sharp leading edge and a soft fade behind it. `x` / `y` place the centre anywhere, including off-frame. | `blades`, `twist`, `depth`, `scale`, `wobble`, `x`, `y`, `grain` |
|
|
42
|
+
|
|
43
|
+
Previews of every look, with full param ranges, are in the
|
|
44
|
+
[repository README](https://github.com/ugolbck/instantshader#readme).
|
|
45
|
+
|
|
46
|
+
Every shader takes the same mount options; `params` is where they differ:
|
|
47
|
+
|
|
48
|
+
```ts
|
|
49
|
+
import { mountGradient, bloom } from "instantshader";
|
|
50
|
+
|
|
51
|
+
mountGradient(el, {
|
|
52
|
+
shader: bloom,
|
|
53
|
+
colors: ["#ffd9e8", "#ffb300", "#ff8fc0", "#3d7bff", "#0a2e14"],
|
|
54
|
+
// bloom has two independent motion modes — petals that breathe and lean,
|
|
55
|
+
// and colours that travel outward through a still pattern. Mix freely.
|
|
56
|
+
params: { sway: 0.5, colorflow: 0.4 },
|
|
57
|
+
});
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
Ranges, defaults and labels are all discoverable at runtime — `shader.params`
|
|
61
|
+
is an array of `ParamDef`, and `shader.randomParams(rand)` produces a full,
|
|
62
|
+
sensible param set for "randomize" flows. `shaders` and `getShader(id)` expose
|
|
63
|
+
the whole registry (importing either pulls every shader).
|
|
64
|
+
|
|
26
65
|
## Seamless loops
|
|
27
66
|
|
|
28
67
|
Set `loopSeconds` and the animation repeats exactly, with no visible seam at
|
|
@@ -68,5 +107,13 @@ Notes:
|
|
|
68
107
|
- **`beam` freezes its width swell below ~29s.** Its natural cycle is ~57s and
|
|
69
108
|
cannot be squeezed into a short loop without becoming a throb, so under that
|
|
70
109
|
threshold the swell holds still instead. Everything else still animates.
|
|
110
|
+
- **`bloom` sheds parts of its sway on short loops.** Its `sway` is several
|
|
111
|
+
slow oscillations (petal breathing ~20s, fan lean ~30s, petal flex ~42s)
|
|
112
|
+
layered over a noise wander. Each oscillation holds still once the loop is
|
|
113
|
+
shorter than about half its own period, so below ~10s the wander is the only
|
|
114
|
+
thing left moving. `colorflow` is unaffected — it always fits at least one
|
|
115
|
+
full cycle into the loop, flowing faster on a short one.
|
|
116
|
+
- `halo`, `dune` and `whorl` always complete at least one full cycle of their
|
|
117
|
+
main motion per loop, so a short loop simply runs them faster.
|
|
71
118
|
- Any loop necessarily revisits the same state every N seconds; a long period
|
|
72
119
|
is what buys the impression of never repeating.
|
package/dist/index.d.ts
CHANGED
|
@@ -126,6 +126,18 @@ declare const beam: ShaderDef;
|
|
|
126
126
|
//#region src/shaders/bloom.d.ts
|
|
127
127
|
declare const bloom: ShaderDef;
|
|
128
128
|
//#endregion
|
|
129
|
+
//#region src/shaders/halo.d.ts
|
|
130
|
+
declare const halo: ShaderDef;
|
|
131
|
+
//#endregion
|
|
132
|
+
//#region src/shaders/strata.d.ts
|
|
133
|
+
declare const strata: ShaderDef;
|
|
134
|
+
//#endregion
|
|
135
|
+
//#region src/shaders/dune.d.ts
|
|
136
|
+
declare const dune: ShaderDef;
|
|
137
|
+
//#endregion
|
|
138
|
+
//#region src/shaders/whorl.d.ts
|
|
139
|
+
declare const whorl: ShaderDef;
|
|
140
|
+
//#endregion
|
|
129
141
|
//#region src/registry.d.ts
|
|
130
142
|
declare const shaders: readonly ShaderDef[];
|
|
131
143
|
declare function getShader(id: string): ShaderDef | undefined;
|
|
@@ -191,4 +203,4 @@ declare function renderGradientFrame(opts: {
|
|
|
191
203
|
*/
|
|
192
204
|
declare function buildPaletteRamp(colors: string[]): Uint8Array;
|
|
193
205
|
//#endregion
|
|
194
|
-
export { type MountHandle, type MountOptions, type ParamDef, type RenderFrameResult, type Renderer, type RendererOptions, type ShaderDef, beam, bloom, buildPaletteRamp, createRenderer, flow, getShader, mountGradient, renderGradientFrame, shaders };
|
|
206
|
+
export { type MountHandle, type MountOptions, type ParamDef, type RenderFrameResult, type Renderer, type RendererOptions, type ShaderDef, beam, bloom, buildPaletteRamp, createRenderer, dune, flow, getShader, halo, mountGradient, renderGradientFrame, shaders, strata, whorl };
|
package/dist/index.js
CHANGED
|
@@ -187,10 +187,74 @@ float grain(vec2 uv, float time) {
|
|
|
187
187
|
return fract(sin(dot(st, vec2(12.9898, 78.233))) * 43758.5453);
|
|
188
188
|
}
|
|
189
189
|
`;
|
|
190
|
+
/**
|
|
191
|
+
* Isotropic frame helpers, shared by every look whose composition is a SHAPE
|
|
192
|
+
* rather than a frame-filling field. worldUv() is 0-1 on both axes of a 16:9
|
|
193
|
+
* world, so raw uv stretches x by 1.78 -- circles render as ellipses and a
|
|
194
|
+
* rotated stripe changes thickness with its angle. isoCoord() scales x by the
|
|
195
|
+
* world aspect so a unit circle is a screen circle (frame half-height = 0.5),
|
|
196
|
+
* and isoHalf() is the frame's visible half-extents in that space, mirroring
|
|
197
|
+
* worldUv()'s cover fit so a square tile and a 16:9 export agree on where the
|
|
198
|
+
* edges are.
|
|
199
|
+
*/
|
|
200
|
+
const ISO = `
|
|
201
|
+
const float WORLD_ASPECT = 1000.0 / 562.5;
|
|
202
|
+
vec2 isoCoord(vec2 uv) { return (uv - 0.5) * vec2(WORLD_ASPECT, 1.0); }
|
|
203
|
+
vec2 isoHalf() {
|
|
204
|
+
float canvasAspect = u_resolution.x / u_resolution.y;
|
|
205
|
+
return vec2(0.5 * min(1.0, canvasAspect / WORLD_ASPECT),
|
|
206
|
+
0.5 * min(1.0, WORLD_ASPECT / canvasAspect))
|
|
207
|
+
* vec2(WORLD_ASPECT, 1.0);
|
|
208
|
+
}
|
|
209
|
+
`;
|
|
210
|
+
/**
|
|
211
|
+
* A phase angle that advances at ~w rad/s and is exactly periodic over the
|
|
212
|
+
* loop -- for HEADLINE motions (a travelling wave, an orbiting colour) that
|
|
213
|
+
* must never freeze. This is the opposite trade to loopFreq, which rounds to
|
|
214
|
+
* zero on short loops to protect slow secondary swells from turning into a
|
|
215
|
+
* throb: here the cycle count is floored at one, so a short loop simply runs
|
|
216
|
+
* the motion faster.
|
|
217
|
+
*
|
|
218
|
+
* The count is also forced ODD. With an even count the phase at half-cycle is
|
|
219
|
+
* a whole number of turns, i.e. the frame at loop/2 would be identical to the
|
|
220
|
+
* frame at 0 for anything driven by this angle alone -- the loop would
|
|
221
|
+
* secretly be half as long as asked for.
|
|
222
|
+
*
|
|
223
|
+
* Not looping, w is snapped to a whole number of turns per 1000s, because
|
|
224
|
+
* u_time itself wraps there (see renderer.ts) and an unsnapped phase would
|
|
225
|
+
* jump once every ~16.7 minutes.
|
|
226
|
+
*/
|
|
227
|
+
const LOOP_ANGLE = `
|
|
228
|
+
float loopAngle(float w) {
|
|
229
|
+
if (u_loop <= 0.0) return TAU * floor(w * 1000.0 / TAU + 0.5) * (u_time / 1000.0);
|
|
230
|
+
float n = 2.0 * floor(w * u_loop / TAU * 0.5) + 1.0;
|
|
231
|
+
return TAU * n * (u_time / u_loop);
|
|
232
|
+
}
|
|
233
|
+
`;
|
|
234
|
+
/**
|
|
235
|
+
* Seed decorrelation. Adding u_seed straight onto a noise coordinate makes
|
|
236
|
+
* the seed a PAN: neighbouring seeds show the same field slid sideways, so a
|
|
237
|
+
* seed slider reads as "moves the picture a bit" instead of "new picture".
|
|
238
|
+
* seedOffset() hashes the seed into an unrelated point of the noise plane, so
|
|
239
|
+
* any change of seed lands on a composition with nothing in common with the
|
|
240
|
+
* last one. seedHash(i) is the scalar version, one independent 0-1 value per
|
|
241
|
+
* channel i, for seeded angles and phases.
|
|
242
|
+
*
|
|
243
|
+
* The offset stays inside [8, 72), far below the ~1000 ceiling where snoise's
|
|
244
|
+
* float precision gives out (see the note at the top of this file).
|
|
245
|
+
*/
|
|
246
|
+
const SEED = `
|
|
247
|
+
float seedHash(float i) {
|
|
248
|
+
return fract(sin(u_seed * 12.9898 + i * 78.233) * 43758.5453);
|
|
249
|
+
}
|
|
250
|
+
vec2 seedOffset() {
|
|
251
|
+
return vec2(seedHash(11.0), seedHash(23.0)) * 64.0 + 8.0;
|
|
252
|
+
}
|
|
253
|
+
`;
|
|
190
254
|
|
|
191
255
|
//#endregion
|
|
192
256
|
//#region src/shaders/flow.ts
|
|
193
|
-
const FRAGMENT$
|
|
257
|
+
const FRAGMENT$6 = `
|
|
194
258
|
uniform float u_scale;
|
|
195
259
|
uniform float u_curl;
|
|
196
260
|
uniform float u_drift;
|
|
@@ -327,7 +391,7 @@ void main() {
|
|
|
327
391
|
const flow = {
|
|
328
392
|
id: "flow",
|
|
329
393
|
label: "Flow",
|
|
330
|
-
fragment: FRAGMENT$
|
|
394
|
+
fragment: FRAGMENT$6,
|
|
331
395
|
params: [
|
|
332
396
|
{
|
|
333
397
|
key: "scale",
|
|
@@ -383,7 +447,7 @@ const flow = {
|
|
|
383
447
|
|
|
384
448
|
//#endregion
|
|
385
449
|
//#region src/shaders/beam.ts
|
|
386
|
-
const FRAGMENT$
|
|
450
|
+
const FRAGMENT$5 = `
|
|
387
451
|
uniform float u_scale;
|
|
388
452
|
uniform float u_width;
|
|
389
453
|
uniform float u_glow;
|
|
@@ -637,7 +701,7 @@ void main() {
|
|
|
637
701
|
const beam = {
|
|
638
702
|
id: "beam",
|
|
639
703
|
label: "Beam",
|
|
640
|
-
fragment: FRAGMENT$
|
|
704
|
+
fragment: FRAGMENT$5,
|
|
641
705
|
params: [
|
|
642
706
|
{
|
|
643
707
|
key: "scale",
|
|
@@ -693,7 +757,7 @@ const beam = {
|
|
|
693
757
|
|
|
694
758
|
//#endregion
|
|
695
759
|
//#region src/shaders/bloom.ts
|
|
696
|
-
const FRAGMENT = `
|
|
760
|
+
const FRAGMENT$4 = `
|
|
697
761
|
uniform float u_scale;
|
|
698
762
|
uniform float u_petals;
|
|
699
763
|
uniform float u_pinch;
|
|
@@ -852,7 +916,7 @@ void main() {
|
|
|
852
916
|
const bloom = {
|
|
853
917
|
id: "bloom",
|
|
854
918
|
label: "Bloom",
|
|
855
|
-
fragment: FRAGMENT,
|
|
919
|
+
fragment: FRAGMENT$4,
|
|
856
920
|
params: [
|
|
857
921
|
{
|
|
858
922
|
key: "scale",
|
|
@@ -924,12 +988,688 @@ const bloom = {
|
|
|
924
988
|
}
|
|
925
989
|
};
|
|
926
990
|
|
|
991
|
+
//#endregion
|
|
992
|
+
//#region src/shaders/halo.ts
|
|
993
|
+
const FRAGMENT$3 = `
|
|
994
|
+
uniform float u_radius;
|
|
995
|
+
uniform float u_x;
|
|
996
|
+
uniform float u_y;
|
|
997
|
+
uniform float u_glow;
|
|
998
|
+
uniform float u_crescent;
|
|
999
|
+
uniform float u_flares;
|
|
1000
|
+
uniform float u_grain;
|
|
1001
|
+
|
|
1002
|
+
${SIMPLEX_2D}
|
|
1003
|
+
${PERIODIC_2D}
|
|
1004
|
+
${GRAIN}
|
|
1005
|
+
${ISO}
|
|
1006
|
+
${LOOP_ANGLE}
|
|
1007
|
+
${SEED}
|
|
1008
|
+
|
|
1009
|
+
const float PI = 3.14159265;
|
|
1010
|
+
const vec3 LUMA = vec3(0.2126, 0.7152, 0.0722);
|
|
1011
|
+
|
|
1012
|
+
void main() {
|
|
1013
|
+
vec2 uv = worldUv();
|
|
1014
|
+
vec2 p = isoCoord(uv);
|
|
1015
|
+
vec2 halfIso = isoHalf();
|
|
1016
|
+
|
|
1017
|
+
vec2 so = seedOffset();
|
|
1018
|
+
vec2 drift = loopDrift(0.04, vec2(1.0, 0.0));
|
|
1019
|
+
|
|
1020
|
+
// ---- the disc -----------------------------------------------------------
|
|
1021
|
+
float R = u_radius;
|
|
1022
|
+
vec2 c = vec2(u_x, u_y) * (halfIso + R);
|
|
1023
|
+
|
|
1024
|
+
vec2 rel = p - c;
|
|
1025
|
+
float r = length(rel);
|
|
1026
|
+
float theta = atan(rel.y, rel.x);
|
|
1027
|
+
float d = r - R;
|
|
1028
|
+
|
|
1029
|
+
// ---- streamers ----------------------------------------------------------
|
|
1030
|
+
// A = 14 angular periods; radial tile 4. The second octave doubles both
|
|
1031
|
+
// the frequency and the tile, and travels twice as far per loop, so it
|
|
1032
|
+
// lands on a whole tile too.
|
|
1033
|
+
float A = 14.0;
|
|
1034
|
+
// 0.7: radial features ~6x longer than they are wide at A = 14, which is
|
|
1035
|
+
// the anisotropy that reads as RAYS. At 2.2 the cells were near-square in
|
|
1036
|
+
// log-polar space and the corona rendered as cloud.
|
|
1037
|
+
float rho = log(max(r, 0.001) / R) * 0.7;
|
|
1038
|
+
float flowOut = loopTravel(0.04, vec2(0.0, 1.0), 4.0).y;
|
|
1039
|
+
vec2 sp = vec2((theta / TAU + 0.5) * A, rho - flowOut + so.x);
|
|
1040
|
+
float fl = pnoise(sp, vec2(A, 4.0)) + 0.5 * pnoise(sp * 2.0, vec2(2.0 * A, 8.0));
|
|
1041
|
+
|
|
1042
|
+
float len = (0.03 + 0.3 * u_glow) * max(1.0 + 1.5 * u_flares * fl, 0.15);
|
|
1043
|
+
float outside = max(d, 0.0);
|
|
1044
|
+
float corona = exp(-outside / len);
|
|
1045
|
+
float veil = 0.18 * exp(-outside / (3.5 * len));
|
|
1046
|
+
float inner = 0.4 * exp(min(d, 0.0) / (0.025 + 0.09 * u_glow));
|
|
1047
|
+
float limb = exp(-abs(d) / 0.007);
|
|
1048
|
+
|
|
1049
|
+
// One-pixel soft disc edge, in frame units.
|
|
1050
|
+
float pixel = 2.0 * halfIso.y / u_resolution.y;
|
|
1051
|
+
float isOut = smoothstep(-pixel, pixel, d);
|
|
1052
|
+
|
|
1053
|
+
// ---- crescent -----------------------------------------------------------
|
|
1054
|
+
// Light direction as a VECTOR blend (no angle wrap to worry about): the
|
|
1055
|
+
// seeded direction for a centred disc, handing over to "toward the frame
|
|
1056
|
+
// centre" as the disc moves off it, plus a slow sway.
|
|
1057
|
+
float aSeed = seedHash(1.0) * TAU;
|
|
1058
|
+
float off = length(c);
|
|
1059
|
+
float sway = 0.35 * snoise(vec2(so.y, 1.0) + drift);
|
|
1060
|
+
vec2 inward = -c / max(off, 0.0001);
|
|
1061
|
+
inward = vec2(inward.x * cos(sway) - inward.y * sin(sway),
|
|
1062
|
+
inward.x * sin(sway) + inward.y * cos(sway));
|
|
1063
|
+
vec2 seedDir = vec2(cos(aSeed + sway), sin(aSeed + sway));
|
|
1064
|
+
vec2 dirL = normalize(mix(seedDir, inward, smoothstep(0.05, 0.5, off)) + seedDir * 0.0001);
|
|
1065
|
+
float facing = 0.5 + 0.5 * dot(rel / max(r, 0.0001), dirL);
|
|
1066
|
+
float arc = mix(1.0, 0.03 + 0.97 * facing * facing * facing, u_crescent);
|
|
1067
|
+
|
|
1068
|
+
// ---- palette by azimuth -------------------------------------------------
|
|
1069
|
+
float theta0 = loopAngle(0.1) + seedHash(2.0) * TAU;
|
|
1070
|
+
float tA = 0.5 + 0.5 * cos(theta - theta0 + 0.7 * u_flares * fl);
|
|
1071
|
+
float t = clamp(tA * 0.85 + 0.15 * (1.0 - exp(-outside * 3.0)), 0.0, 1.0);
|
|
1072
|
+
vec3 col = palette(t);
|
|
1073
|
+
float lum = dot(col, LUMA);
|
|
1074
|
+
|
|
1075
|
+
// ---- background: the ramp's darkest stop, crushed (as in beam) ----------
|
|
1076
|
+
vec3 cA = palette(0.0);
|
|
1077
|
+
vec3 cB = palette(0.5);
|
|
1078
|
+
vec3 cC = palette(1.0);
|
|
1079
|
+
float lA = dot(cA, LUMA);
|
|
1080
|
+
float lB = dot(cB, LUMA);
|
|
1081
|
+
float lC = dot(cC, LUMA);
|
|
1082
|
+
vec3 dk = mix(cA, cB, step(lB, lA));
|
|
1083
|
+
dk = mix(dk, cC, step(lC, min(lA, lB)));
|
|
1084
|
+
vec3 color = dk * 0.1;
|
|
1085
|
+
|
|
1086
|
+
// ---- additive light -----------------------------------------------------
|
|
1087
|
+
// gain/boost: see beam.ts -- bright banks are divided down before they can
|
|
1088
|
+
// clip, dark banks are multiplied up (chroma-preserving) before they vanish.
|
|
1089
|
+
float gain = 1.0 / (1.0 + 1.2 * lum * lum);
|
|
1090
|
+
float boost = 1.0 + 2.0 * (1.0 - lum) * (1.0 - lum) * (1.0 - lum);
|
|
1091
|
+
float radiance = mix(inner, corona + veil, isOut);
|
|
1092
|
+
color += col * radiance * arc * gain * boost * 1.35;
|
|
1093
|
+
// The limb is the hottest thing in frame: palette colour plus a dark-gated
|
|
1094
|
+
// white lift, so it still reads as a filament on near-black banks.
|
|
1095
|
+
color += (col * 0.8 + vec3(0.35 * (1.0 - lum))) * limb * arc;
|
|
1096
|
+
|
|
1097
|
+
float g = grain(uv, u_time) - 0.5;
|
|
1098
|
+
color += g * u_grain;
|
|
1099
|
+
|
|
1100
|
+
gl_FragColor = vec4(clamp(color, 0.0, 1.0), 1.0);
|
|
1101
|
+
}
|
|
1102
|
+
`;
|
|
1103
|
+
const halo = {
|
|
1104
|
+
id: "halo",
|
|
1105
|
+
label: "Halo",
|
|
1106
|
+
fragment: FRAGMENT$3,
|
|
1107
|
+
params: [
|
|
1108
|
+
{
|
|
1109
|
+
key: "radius",
|
|
1110
|
+
label: "Radius",
|
|
1111
|
+
min: .12,
|
|
1112
|
+
max: 1.6,
|
|
1113
|
+
step: .01,
|
|
1114
|
+
default: 1
|
|
1115
|
+
},
|
|
1116
|
+
{
|
|
1117
|
+
key: "x",
|
|
1118
|
+
label: "X",
|
|
1119
|
+
min: -1,
|
|
1120
|
+
max: 1,
|
|
1121
|
+
step: .01,
|
|
1122
|
+
default: 0
|
|
1123
|
+
},
|
|
1124
|
+
{
|
|
1125
|
+
key: "y",
|
|
1126
|
+
label: "Y",
|
|
1127
|
+
min: -1,
|
|
1128
|
+
max: 1,
|
|
1129
|
+
step: .01,
|
|
1130
|
+
default: -.78
|
|
1131
|
+
},
|
|
1132
|
+
{
|
|
1133
|
+
key: "glow",
|
|
1134
|
+
label: "Glow",
|
|
1135
|
+
min: 0,
|
|
1136
|
+
max: 1,
|
|
1137
|
+
step: .01,
|
|
1138
|
+
default: .5
|
|
1139
|
+
},
|
|
1140
|
+
{
|
|
1141
|
+
key: "crescent",
|
|
1142
|
+
label: "Crescent",
|
|
1143
|
+
min: 0,
|
|
1144
|
+
max: 1,
|
|
1145
|
+
step: .01,
|
|
1146
|
+
default: .35
|
|
1147
|
+
},
|
|
1148
|
+
{
|
|
1149
|
+
key: "flares",
|
|
1150
|
+
label: "Flares",
|
|
1151
|
+
min: 0,
|
|
1152
|
+
max: 1,
|
|
1153
|
+
step: .01,
|
|
1154
|
+
default: .5
|
|
1155
|
+
},
|
|
1156
|
+
{
|
|
1157
|
+
key: "grain",
|
|
1158
|
+
label: "Grain",
|
|
1159
|
+
min: 0,
|
|
1160
|
+
max: .3,
|
|
1161
|
+
step: .01,
|
|
1162
|
+
default: .08
|
|
1163
|
+
}
|
|
1164
|
+
],
|
|
1165
|
+
randomParams(rand) {
|
|
1166
|
+
const horizon = rand() < .6;
|
|
1167
|
+
return {
|
|
1168
|
+
radius: horizon ? .7 + rand() * .8 : .18 + rand() * .24,
|
|
1169
|
+
x: horizon ? -.3 + rand() * .6 : -.4 + rand() * .8,
|
|
1170
|
+
y: horizon ? -.86 + rand() * .16 : -.2 + rand() * .4,
|
|
1171
|
+
glow: .3 + rand() * .6000000000000001,
|
|
1172
|
+
crescent: rand() * .9,
|
|
1173
|
+
flares: .2 + rand() * .7,
|
|
1174
|
+
grain: .08
|
|
1175
|
+
};
|
|
1176
|
+
}
|
|
1177
|
+
};
|
|
1178
|
+
|
|
1179
|
+
//#endregion
|
|
1180
|
+
//#region src/shaders/strata.ts
|
|
1181
|
+
const FRAGMENT$2 = `
|
|
1182
|
+
uniform float u_scale;
|
|
1183
|
+
uniform float u_layers;
|
|
1184
|
+
uniform float u_warp;
|
|
1185
|
+
uniform float u_ridges;
|
|
1186
|
+
uniform float u_stretch;
|
|
1187
|
+
uniform float u_depth;
|
|
1188
|
+
uniform float u_blend;
|
|
1189
|
+
uniform float u_angle;
|
|
1190
|
+
uniform float u_grain;
|
|
1191
|
+
|
|
1192
|
+
${SIMPLEX_2D}
|
|
1193
|
+
${FBM}
|
|
1194
|
+
${SHAPE}
|
|
1195
|
+
${GRAIN}
|
|
1196
|
+
${ISO}
|
|
1197
|
+
${SEED}
|
|
1198
|
+
|
|
1199
|
+
const float PI = 3.14159265;
|
|
1200
|
+
|
|
1201
|
+
float field(vec2 q) {
|
|
1202
|
+
float n = fbm2(q);
|
|
1203
|
+
// Ridged transform of the SAME sample (free): constants chosen so its mean
|
|
1204
|
+
// and spread roughly match the fbm's, keeping spread()'s equal-area promise
|
|
1205
|
+
// approximately true at any mix.
|
|
1206
|
+
float ridge = 0.55 - 1.6 * abs(n);
|
|
1207
|
+
return spread(mix(n, ridge, u_ridges), 0.35); // 0.35 = fbm2's standard deviation
|
|
1208
|
+
}
|
|
1209
|
+
|
|
1210
|
+
// Frame-space vector -> field-space vector: rotate onto the seeded stretch
|
|
1211
|
+
// axis, then compress along it. Used for positions AND for the tap offsets,
|
|
1212
|
+
// so shadows keep their true on-screen length however stretched the field is.
|
|
1213
|
+
vec2 toField(vec2 v, vec2 axis) {
|
|
1214
|
+
return vec2(dot(v, axis) / (1.0 + 3.0 * u_stretch), dot(v, vec2(-axis.y, axis.x)));
|
|
1215
|
+
}
|
|
1216
|
+
|
|
1217
|
+
void main() {
|
|
1218
|
+
vec2 uv = worldUv();
|
|
1219
|
+
vec2 iso = isoCoord(uv);
|
|
1220
|
+
|
|
1221
|
+
vec2 drift = loopDrift(0.03, vec2(1.0, 0.0));
|
|
1222
|
+
float freq = 0.8 * u_scale;
|
|
1223
|
+
|
|
1224
|
+
// Domain warp, evaluated ONCE and shared by every tap below. The taps are
|
|
1225
|
+
// at most ~0.07 frame units apart, over which a 0.5x-frequency warp is
|
|
1226
|
+
// effectively constant -- re-evaluating it per tap would cost 6 more
|
|
1227
|
+
// snoise calls to move each tap by a fraction of a pixel.
|
|
1228
|
+
float axisAngle = seedHash(5.0) * PI;
|
|
1229
|
+
vec2 axis = vec2(cos(axisAngle), sin(axisAngle));
|
|
1230
|
+
vec2 fp = toField(iso, axis);
|
|
1231
|
+
vec2 so = seedOffset();
|
|
1232
|
+
vec2 wq = fp * (0.5 * u_scale) + so.yx + 40.0 - drift.yx;
|
|
1233
|
+
vec2 warp = u_warp * 0.45 * vec2(snoise(wq), snoise(wq + vec2(13.1, 7.7)));
|
|
1234
|
+
vec2 q = fp * freq + so + drift + warp;
|
|
1235
|
+
|
|
1236
|
+
float L = floor(u_layers + 0.5);
|
|
1237
|
+
|
|
1238
|
+
// Direction TOWARD the light, and the shadow length in frame units.
|
|
1239
|
+
float ang = u_angle * PI / 180.0;
|
|
1240
|
+
vec2 toLight = vec2(cos(ang), sin(ang));
|
|
1241
|
+
vec2 side = vec2(-toLight.y, toLight.x);
|
|
1242
|
+
float reach = 0.012 + 0.06 * u_depth;
|
|
1243
|
+
vec2 qLight = toField(toLight * reach, axis) * freq;
|
|
1244
|
+
vec2 qSide = toField(side * reach, axis) * freq;
|
|
1245
|
+
|
|
1246
|
+
float v = field(q) * L;
|
|
1247
|
+
float vFar = field(q + qLight) * L; // shadow tap
|
|
1248
|
+
float vNear = field(q + qLight * 0.3) * L; // rim tap
|
|
1249
|
+
float vSide = field(q + qSide) * L; // gradient only
|
|
1250
|
+
|
|
1251
|
+
float band = min(floor(v), L - 1.0);
|
|
1252
|
+
float f = v - band;
|
|
1253
|
+
|
|
1254
|
+
// ---- analytic edge AA ---------------------------------------------------
|
|
1255
|
+
// |grad v| per frame unit, from the two orthogonal taps, times the size of
|
|
1256
|
+
// a pixel in frame units (frame height is 2*isoHalf().y over resolution.y).
|
|
1257
|
+
float gradV = length(vec2(vFar - v, vSide - v)) / reach;
|
|
1258
|
+
float pixel = 2.0 * isoHalf().y / u_resolution.y;
|
|
1259
|
+
float aa = clamp(gradV * pixel * 1.5, 0.002, 0.5);
|
|
1260
|
+
float toNext = smoothstep(1.0 - aa, 1.0, f) * step(band, L - 1.5);
|
|
1261
|
+
|
|
1262
|
+
// ---- colour -------------------------------------------------------------
|
|
1263
|
+
float denom = max(L - 1.0, 1.0);
|
|
1264
|
+
float tHere = mix(band / denom, v / L, u_blend);
|
|
1265
|
+
float tNext = mix((band + 1.0) / denom, v / L, u_blend);
|
|
1266
|
+
vec3 color = mix(palette(tHere), palette(tNext), toNext);
|
|
1267
|
+
|
|
1268
|
+
// ---- shadow + rim -------------------------------------------------------
|
|
1269
|
+
// Both fade out across the AA band so the shadow ends exactly where the
|
|
1270
|
+
// upper sheet begins instead of printing a dark fringe onto its edge.
|
|
1271
|
+
float shadow = smoothstep(band + 0.85, band + 1.4, vFar) * (1.0 - toNext);
|
|
1272
|
+
color *= 1.0 - shadow * 0.6 * u_depth;
|
|
1273
|
+
|
|
1274
|
+
float rim = smoothstep(band, band - 0.45, vNear) * step(0.5, band);
|
|
1275
|
+
color += (vec3(1.0) - clamp(color, 0.0, 1.0)) * rim * 0.22 * u_depth;
|
|
1276
|
+
|
|
1277
|
+
float g = grain(uv, u_time) - 0.5;
|
|
1278
|
+
color += g * u_grain;
|
|
1279
|
+
|
|
1280
|
+
gl_FragColor = vec4(clamp(color, 0.0, 1.0), 1.0);
|
|
1281
|
+
}
|
|
1282
|
+
`;
|
|
1283
|
+
const strata = {
|
|
1284
|
+
id: "strata",
|
|
1285
|
+
label: "Strata",
|
|
1286
|
+
fragment: FRAGMENT$2,
|
|
1287
|
+
params: [
|
|
1288
|
+
{
|
|
1289
|
+
key: "scale",
|
|
1290
|
+
label: "Scale",
|
|
1291
|
+
min: .4,
|
|
1292
|
+
max: 2.5,
|
|
1293
|
+
step: .05,
|
|
1294
|
+
default: 1
|
|
1295
|
+
},
|
|
1296
|
+
{
|
|
1297
|
+
key: "layers",
|
|
1298
|
+
label: "Layers",
|
|
1299
|
+
min: 3,
|
|
1300
|
+
max: 16,
|
|
1301
|
+
step: 1,
|
|
1302
|
+
default: 7
|
|
1303
|
+
},
|
|
1304
|
+
{
|
|
1305
|
+
key: "warp",
|
|
1306
|
+
label: "Warp",
|
|
1307
|
+
min: 0,
|
|
1308
|
+
max: 1,
|
|
1309
|
+
step: .01,
|
|
1310
|
+
default: .5
|
|
1311
|
+
},
|
|
1312
|
+
{
|
|
1313
|
+
key: "ridges",
|
|
1314
|
+
label: "Ridges",
|
|
1315
|
+
min: 0,
|
|
1316
|
+
max: 1,
|
|
1317
|
+
step: .01,
|
|
1318
|
+
default: .25
|
|
1319
|
+
},
|
|
1320
|
+
{
|
|
1321
|
+
key: "stretch",
|
|
1322
|
+
label: "Stretch",
|
|
1323
|
+
min: 0,
|
|
1324
|
+
max: 1,
|
|
1325
|
+
step: .01,
|
|
1326
|
+
default: .2
|
|
1327
|
+
},
|
|
1328
|
+
{
|
|
1329
|
+
key: "depth",
|
|
1330
|
+
label: "Depth",
|
|
1331
|
+
min: 0,
|
|
1332
|
+
max: 1,
|
|
1333
|
+
step: .01,
|
|
1334
|
+
default: .6
|
|
1335
|
+
},
|
|
1336
|
+
{
|
|
1337
|
+
key: "blend",
|
|
1338
|
+
label: "Blend",
|
|
1339
|
+
min: 0,
|
|
1340
|
+
max: 1,
|
|
1341
|
+
step: .01,
|
|
1342
|
+
default: .15
|
|
1343
|
+
},
|
|
1344
|
+
{
|
|
1345
|
+
key: "angle",
|
|
1346
|
+
label: "Light",
|
|
1347
|
+
min: 0,
|
|
1348
|
+
max: 360,
|
|
1349
|
+
step: 1,
|
|
1350
|
+
default: 125
|
|
1351
|
+
},
|
|
1352
|
+
{
|
|
1353
|
+
key: "grain",
|
|
1354
|
+
label: "Grain",
|
|
1355
|
+
min: 0,
|
|
1356
|
+
max: .3,
|
|
1357
|
+
step: .01,
|
|
1358
|
+
default: .06
|
|
1359
|
+
}
|
|
1360
|
+
],
|
|
1361
|
+
randomParams(rand) {
|
|
1362
|
+
return {
|
|
1363
|
+
scale: .6 + rand() * 1.2000000000000002,
|
|
1364
|
+
layers: Math.floor(4 + rand() * 9),
|
|
1365
|
+
warp: rand() * 1,
|
|
1366
|
+
ridges: rand() * 1,
|
|
1367
|
+
stretch: rand() * rand(),
|
|
1368
|
+
depth: .35 + rand() * .65,
|
|
1369
|
+
blend: rand() * .6,
|
|
1370
|
+
angle: Math.floor(rand() * 360),
|
|
1371
|
+
grain: .06
|
|
1372
|
+
};
|
|
1373
|
+
}
|
|
1374
|
+
};
|
|
1375
|
+
|
|
1376
|
+
//#endregion
|
|
1377
|
+
//#region src/shaders/dune.ts
|
|
1378
|
+
const FRAGMENT$1 = `
|
|
1379
|
+
uniform float u_layers;
|
|
1380
|
+
uniform float u_swell;
|
|
1381
|
+
uniform float u_waves;
|
|
1382
|
+
uniform float u_fade;
|
|
1383
|
+
uniform float u_soft;
|
|
1384
|
+
uniform float u_angle;
|
|
1385
|
+
uniform float u_grain;
|
|
1386
|
+
|
|
1387
|
+
${GRAIN}
|
|
1388
|
+
${ISO}
|
|
1389
|
+
${LOOP_ANGLE}
|
|
1390
|
+
${SEED}
|
|
1391
|
+
|
|
1392
|
+
const float PI = 3.14159265;
|
|
1393
|
+
|
|
1394
|
+
void main() {
|
|
1395
|
+
vec2 uv = worldUv();
|
|
1396
|
+
vec2 iso = isoCoord(uv);
|
|
1397
|
+
vec2 halfIso = isoHalf();
|
|
1398
|
+
|
|
1399
|
+
// Layer frame: x runs along the crests, y is "up", normalised so the
|
|
1400
|
+
// visible frame spans y = -1..1 at every angle and aspect.
|
|
1401
|
+
float ang = u_angle * PI / 180.0;
|
|
1402
|
+
vec2 ax = vec2(cos(ang), sin(ang));
|
|
1403
|
+
vec2 ay = vec2(-ax.y, ax.x);
|
|
1404
|
+
float spanY = halfIso.x * abs(ay.x) + halfIso.y * abs(ay.y);
|
|
1405
|
+
float x = dot(iso, ax);
|
|
1406
|
+
float y = dot(iso, ay) / spanY;
|
|
1407
|
+
|
|
1408
|
+
float n = floor(u_layers + 0.5);
|
|
1409
|
+
float a1 = loopAngle(0.22);
|
|
1410
|
+
float a2 = loopAngle(0.36);
|
|
1411
|
+
float k = PI * u_waves;
|
|
1412
|
+
|
|
1413
|
+
float pixel = 2.0 * halfIso.y / u_resolution.y / spanY;
|
|
1414
|
+
float w = pixel + u_soft * 0.22;
|
|
1415
|
+
|
|
1416
|
+
// Sky: the first stop, itself graded a little so it is not a flat fill.
|
|
1417
|
+
vec3 color = palette(0.04 * (1.0 - y));
|
|
1418
|
+
|
|
1419
|
+
for (int li = 0; li < 12; li++) {
|
|
1420
|
+
float i = float(li);
|
|
1421
|
+
if (i >= n) break;
|
|
1422
|
+
|
|
1423
|
+
float h1 = seedHash(i * 3.0 + 1.0);
|
|
1424
|
+
float h2 = seedHash(i * 3.0 + 2.0);
|
|
1425
|
+
float h3 = seedHash(i * 3.0 + 3.0);
|
|
1426
|
+
|
|
1427
|
+
// Crest baselines spread from near the top to near the bottom.
|
|
1428
|
+
float base = mix(0.72, -0.8, i / max(n - 1.0, 1.0));
|
|
1429
|
+
float fi = k * (0.75 + 0.5 * h1);
|
|
1430
|
+
float dir = h3 < 0.5 ? -1.0 : 1.0;
|
|
1431
|
+
float edge = base + u_swell * 0.5 * (0.6 * sin(fi * x + h2 * TAU + dir * a1)
|
|
1432
|
+
+ 0.4 * sin(fi * 1.7 * x + h3 * TAU - a2));
|
|
1433
|
+
|
|
1434
|
+
float depth = edge - y;
|
|
1435
|
+
float coverage = smoothstep(-w, w, depth);
|
|
1436
|
+
|
|
1437
|
+
float ti = (i + 1.0) / n;
|
|
1438
|
+
float body = 1.0 - exp(-max(depth, 0.0) / 0.3);
|
|
1439
|
+
// Lengthwise drift: the crest colour wanders a third of a stop along x.
|
|
1440
|
+
float along = 0.35 * sin(x * 1.1 + h1 * TAU + dir * a2);
|
|
1441
|
+
float t = ti + (along - u_fade * 1.15 * body) / n;
|
|
1442
|
+
|
|
1443
|
+
color = mix(color, palette(clamp(t, 0.0, 1.0)), coverage);
|
|
1444
|
+
}
|
|
1445
|
+
|
|
1446
|
+
float g = grain(uv, u_time) - 0.5;
|
|
1447
|
+
color += g * u_grain;
|
|
1448
|
+
|
|
1449
|
+
gl_FragColor = vec4(clamp(color, 0.0, 1.0), 1.0);
|
|
1450
|
+
}
|
|
1451
|
+
`;
|
|
1452
|
+
const dune = {
|
|
1453
|
+
id: "dune",
|
|
1454
|
+
label: "Dune",
|
|
1455
|
+
fragment: FRAGMENT$1,
|
|
1456
|
+
params: [
|
|
1457
|
+
{
|
|
1458
|
+
key: "layers",
|
|
1459
|
+
label: "Layers",
|
|
1460
|
+
min: 2,
|
|
1461
|
+
max: 12,
|
|
1462
|
+
step: 1,
|
|
1463
|
+
default: 6
|
|
1464
|
+
},
|
|
1465
|
+
{
|
|
1466
|
+
key: "swell",
|
|
1467
|
+
label: "Swell",
|
|
1468
|
+
min: 0,
|
|
1469
|
+
max: 1.6,
|
|
1470
|
+
step: .01,
|
|
1471
|
+
default: .7
|
|
1472
|
+
},
|
|
1473
|
+
{
|
|
1474
|
+
key: "waves",
|
|
1475
|
+
label: "Waves",
|
|
1476
|
+
min: .3,
|
|
1477
|
+
max: 5,
|
|
1478
|
+
step: .05,
|
|
1479
|
+
default: 1.4
|
|
1480
|
+
},
|
|
1481
|
+
{
|
|
1482
|
+
key: "fade",
|
|
1483
|
+
label: "Fade",
|
|
1484
|
+
min: 0,
|
|
1485
|
+
max: 1.5,
|
|
1486
|
+
step: .01,
|
|
1487
|
+
default: .9
|
|
1488
|
+
},
|
|
1489
|
+
{
|
|
1490
|
+
key: "soft",
|
|
1491
|
+
label: "Soft",
|
|
1492
|
+
min: 0,
|
|
1493
|
+
max: 1,
|
|
1494
|
+
step: .01,
|
|
1495
|
+
default: .02
|
|
1496
|
+
},
|
|
1497
|
+
{
|
|
1498
|
+
key: "angle",
|
|
1499
|
+
label: "Angle",
|
|
1500
|
+
min: 0,
|
|
1501
|
+
max: 360,
|
|
1502
|
+
step: 1,
|
|
1503
|
+
default: 352
|
|
1504
|
+
},
|
|
1505
|
+
{
|
|
1506
|
+
key: "grain",
|
|
1507
|
+
label: "Grain",
|
|
1508
|
+
min: 0,
|
|
1509
|
+
max: .3,
|
|
1510
|
+
step: .01,
|
|
1511
|
+
default: .05
|
|
1512
|
+
}
|
|
1513
|
+
],
|
|
1514
|
+
randomParams(rand) {
|
|
1515
|
+
return {
|
|
1516
|
+
layers: Math.floor(4 + rand() * 6),
|
|
1517
|
+
swell: .4 + rand() * .7999999999999999,
|
|
1518
|
+
waves: .7 + rand() * 2.0999999999999996,
|
|
1519
|
+
fade: .6 + rand() * .7000000000000001,
|
|
1520
|
+
soft: rand() < .75 ? rand() * .06 : .2 + rand() * .5,
|
|
1521
|
+
angle: Math.floor((rand() < .7 ? -25 + rand() * 50 : rand() * 360) + 360) % 360,
|
|
1522
|
+
grain: .05
|
|
1523
|
+
};
|
|
1524
|
+
}
|
|
1525
|
+
};
|
|
1526
|
+
|
|
1527
|
+
//#endregion
|
|
1528
|
+
//#region src/shaders/whorl.ts
|
|
1529
|
+
const FRAGMENT = `
|
|
1530
|
+
uniform float u_blades;
|
|
1531
|
+
uniform float u_twist;
|
|
1532
|
+
uniform float u_depth;
|
|
1533
|
+
uniform float u_scale;
|
|
1534
|
+
uniform float u_wobble;
|
|
1535
|
+
uniform float u_x;
|
|
1536
|
+
uniform float u_y;
|
|
1537
|
+
uniform float u_grain;
|
|
1538
|
+
|
|
1539
|
+
${SIMPLEX_2D}
|
|
1540
|
+
${GRAIN}
|
|
1541
|
+
${ISO}
|
|
1542
|
+
${LOOP_ANGLE}
|
|
1543
|
+
${SEED}
|
|
1544
|
+
|
|
1545
|
+
void main() {
|
|
1546
|
+
vec2 uv = worldUv();
|
|
1547
|
+
vec2 p = isoCoord(uv);
|
|
1548
|
+
vec2 halfIso = isoHalf();
|
|
1549
|
+
|
|
1550
|
+
vec2 c = vec2(u_x, u_y) * halfIso;
|
|
1551
|
+
vec2 rel = p - c;
|
|
1552
|
+
float r = max(length(rel), 0.0001);
|
|
1553
|
+
float theta = atan(rel.y, rel.x);
|
|
1554
|
+
|
|
1555
|
+
float k = floor(u_blades + 0.5);
|
|
1556
|
+
float rot = loopAngle(0.5) / k + seedHash(1.0) * TAU;
|
|
1557
|
+
|
|
1558
|
+
vec2 drift = loopDrift(0.035, vec2(1.0, 0.0));
|
|
1559
|
+
float wob = u_wobble * 0.45 * snoise(p * 0.9 + seedOffset() + drift);
|
|
1560
|
+
|
|
1561
|
+
float u = k * ((theta - rot) + u_twist * log(r)) / TAU + wob;
|
|
1562
|
+
float s = u - floor(u);
|
|
1563
|
+
|
|
1564
|
+
// One-pixel blend across the sawtooth's drop (see header, point 3).
|
|
1565
|
+
float pixel = 2.0 * halfIso.y / u_resolution.y;
|
|
1566
|
+
float aa = clamp(k * sqrt(1.0 + u_twist * u_twist) / (TAU * r) * pixel * 1.5, 0.0, 0.5);
|
|
1567
|
+
s *= 1.0 - smoothstep(1.0 - aa, 1.0, s);
|
|
1568
|
+
|
|
1569
|
+
float core = smoothstep(0.0, 0.08, r);
|
|
1570
|
+
float t = (1.0 - exp(-r / (0.6 * u_scale))) + u_depth * 0.5 * (s - 0.5) * core;
|
|
1571
|
+
vec3 color = palette(clamp(t, 0.0, 1.0));
|
|
1572
|
+
|
|
1573
|
+
float g = grain(uv, u_time) - 0.5;
|
|
1574
|
+
color += g * u_grain;
|
|
1575
|
+
|
|
1576
|
+
gl_FragColor = vec4(clamp(color, 0.0, 1.0), 1.0);
|
|
1577
|
+
}
|
|
1578
|
+
`;
|
|
1579
|
+
const whorl = {
|
|
1580
|
+
id: "whorl",
|
|
1581
|
+
label: "Whorl",
|
|
1582
|
+
fragment: FRAGMENT,
|
|
1583
|
+
params: [
|
|
1584
|
+
{
|
|
1585
|
+
key: "blades",
|
|
1586
|
+
label: "Blades",
|
|
1587
|
+
min: 2,
|
|
1588
|
+
max: 24,
|
|
1589
|
+
step: 1,
|
|
1590
|
+
default: 9
|
|
1591
|
+
},
|
|
1592
|
+
{
|
|
1593
|
+
key: "twist",
|
|
1594
|
+
label: "Twist",
|
|
1595
|
+
min: -3,
|
|
1596
|
+
max: 3,
|
|
1597
|
+
step: .05,
|
|
1598
|
+
default: 1.1
|
|
1599
|
+
},
|
|
1600
|
+
{
|
|
1601
|
+
key: "depth",
|
|
1602
|
+
label: "Depth",
|
|
1603
|
+
min: 0,
|
|
1604
|
+
max: 1.5,
|
|
1605
|
+
step: .01,
|
|
1606
|
+
default: .8
|
|
1607
|
+
},
|
|
1608
|
+
{
|
|
1609
|
+
key: "scale",
|
|
1610
|
+
label: "Scale",
|
|
1611
|
+
min: .3,
|
|
1612
|
+
max: 3,
|
|
1613
|
+
step: .05,
|
|
1614
|
+
default: 1.2
|
|
1615
|
+
},
|
|
1616
|
+
{
|
|
1617
|
+
key: "wobble",
|
|
1618
|
+
label: "Wobble",
|
|
1619
|
+
min: 0,
|
|
1620
|
+
max: 1,
|
|
1621
|
+
step: .01,
|
|
1622
|
+
default: .4
|
|
1623
|
+
},
|
|
1624
|
+
{
|
|
1625
|
+
key: "x",
|
|
1626
|
+
label: "X",
|
|
1627
|
+
min: -1.5,
|
|
1628
|
+
max: 1.5,
|
|
1629
|
+
step: .01,
|
|
1630
|
+
default: -.55
|
|
1631
|
+
},
|
|
1632
|
+
{
|
|
1633
|
+
key: "y",
|
|
1634
|
+
label: "Y",
|
|
1635
|
+
min: -1.5,
|
|
1636
|
+
max: 1.5,
|
|
1637
|
+
step: .01,
|
|
1638
|
+
default: -.7
|
|
1639
|
+
},
|
|
1640
|
+
{
|
|
1641
|
+
key: "grain",
|
|
1642
|
+
label: "Grain",
|
|
1643
|
+
min: 0,
|
|
1644
|
+
max: .3,
|
|
1645
|
+
step: .01,
|
|
1646
|
+
default: .06
|
|
1647
|
+
}
|
|
1648
|
+
],
|
|
1649
|
+
randomParams(rand) {
|
|
1650
|
+
return {
|
|
1651
|
+
blades: Math.floor(5 + rand() * 12),
|
|
1652
|
+
twist: (rand() < .5 ? -1 : 1) * (.5 + rand() * 2),
|
|
1653
|
+
depth: .5 + rand() * .7,
|
|
1654
|
+
scale: .8 + rand() * 1.2,
|
|
1655
|
+
wobble: rand() * .8,
|
|
1656
|
+
x: -1.1 + rand() * 2.2,
|
|
1657
|
+
y: -1.1 + rand() * 2.2,
|
|
1658
|
+
grain: .06
|
|
1659
|
+
};
|
|
1660
|
+
}
|
|
1661
|
+
};
|
|
1662
|
+
|
|
927
1663
|
//#endregion
|
|
928
1664
|
//#region src/registry.ts
|
|
929
1665
|
const shaders = [
|
|
930
1666
|
flow,
|
|
931
1667
|
beam,
|
|
932
|
-
bloom
|
|
1668
|
+
bloom,
|
|
1669
|
+
halo,
|
|
1670
|
+
strata,
|
|
1671
|
+
dune,
|
|
1672
|
+
whorl
|
|
933
1673
|
];
|
|
934
1674
|
function getShader(id) {
|
|
935
1675
|
return shaders.find((s) => s.id === id);
|
|
@@ -1580,4 +2320,4 @@ function renderGradientFrame(opts) {
|
|
|
1580
2320
|
}
|
|
1581
2321
|
|
|
1582
2322
|
//#endregion
|
|
1583
|
-
export { beam, bloom, buildPaletteRamp, createRenderer, flow, getShader, mountGradient, renderGradientFrame, shaders };
|
|
2323
|
+
export { beam, bloom, buildPaletteRamp, createRenderer, dune, flow, getShader, halo, mountGradient, renderGradientFrame, shaders, strata, whorl };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "instantshader",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.0",
|
|
4
4
|
"description": "Animated WebGL gradient shaders. Zero dependencies.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
"url": "git+https://github.com/ugolbck/instantshader.git",
|
|
10
10
|
"directory": "packages/core"
|
|
11
11
|
},
|
|
12
|
-
"homepage": "https://instantgradient.com/
|
|
12
|
+
"homepage": "https://instantgradient.com/app",
|
|
13
13
|
"exports": {
|
|
14
14
|
".": {
|
|
15
15
|
"types": "./dist/index.d.ts",
|