instantshader 0.6.0 → 0.7.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 +37 -12
- package/dist/index.d.ts +13 -1
- package/dist/index.js +688 -28
- package/package.json +7 -3
package/README.md
CHANGED
|
@@ -3,7 +3,8 @@
|
|
|
3
3
|
# instantshader
|
|
4
4
|
|
|
5
5
|
Animated WebGL gradient shaders with zero dependencies. Mount a live, resizable
|
|
6
|
-
gradient into any DOM element,
|
|
6
|
+
gradient into any DOM element, put dither, pixelate, halftone or ASCII effects
|
|
7
|
+
over it or over your own image, or render a single frame to a detached canvas
|
|
7
8
|
for export pipelines. Built by [InstantGradient](https://instantgradient.com/app).
|
|
8
9
|
|
|
9
10
|
## Install
|
|
@@ -39,6 +40,10 @@ tree-shake away.
|
|
|
39
40
|
| `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
41
|
| `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
42
|
| `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` |
|
|
43
|
+
| `silk` | Satin folds lit from one side, with an anisotropic sheen that streaks along the threads. The palette is printed on the cloth; light only reveals the relief. | `scale`, `folds`, `depth`, `warp`, `sheen`, `light`, `grain` |
|
|
44
|
+
| `nacre` | Glassy liquid folds whose colour walks through the neighbouring palette stops on every slope, the way mother of pearl shifts with the viewing angle. Only ever shows the ramp's own colours. | `scale`, `flow`, `crease`, `depth`, `iridescence`, `light`, `grain` |
|
|
45
|
+
| `burst` | Thin grainy rays out of one point, each ray its own stop, streaming outward in packets, from a dark tunnel to a white-hot star, straight or twisted into a pinwheel. | `rays`, `sharp`, `glow`, `twist`, `x`, `y`, `grain` |
|
|
46
|
+
| `glint` | A shoal of small angular shards streaming along one curved current on dark, spinning and flashing, each edge fringed with colour. The only particle look. | `size`, `density`, `bend`, `angle`, `speed`, `grain` |
|
|
42
47
|
|
|
43
48
|
Previews of every look, with full param ranges, are in the
|
|
44
49
|
[repository README](https://github.com/ugolbck/instantshader#readme).
|
|
@@ -51,20 +56,22 @@ import { mountGradient, bloom } from "instantshader";
|
|
|
51
56
|
mountGradient(el, {
|
|
52
57
|
shader: bloom,
|
|
53
58
|
colors: ["#ffd9e8", "#ffb300", "#ff8fc0", "#3d7bff", "#0a2e14"],
|
|
54
|
-
// bloom has two independent motion modes
|
|
59
|
+
// bloom has two independent motion modes: petals that breathe and lean,
|
|
55
60
|
// and colours that travel outward through a still pattern. Mix freely.
|
|
56
61
|
params: { sway: 0.5, colorflow: 0.4 },
|
|
57
62
|
});
|
|
58
63
|
```
|
|
59
64
|
|
|
60
|
-
Ranges, defaults and labels are all discoverable at runtime
|
|
65
|
+
Ranges, defaults and labels are all discoverable at runtime. `shader.params`
|
|
61
66
|
is an array of `ParamDef`, and `shader.randomParams(rand)` produces a full,
|
|
62
67
|
sensible param set for "randomize" flows. `shaders` and `getShader(id)` expose
|
|
63
68
|
the whole registry (importing either pulls every shader).
|
|
64
69
|
|
|
65
70
|
## Effects
|
|
66
71
|
|
|
67
|
-
|
|
72
|
+
An effect redraws a picture: a shader's output, or an image, canvas or video
|
|
73
|
+
frame you supply. Four are included: `pixelate`, `dither`, `halftone` and
|
|
74
|
+
`ascii`.
|
|
68
75
|
|
|
69
76
|
```ts
|
|
70
77
|
import { mountStack, bloom, dither } from "instantshader";
|
|
@@ -77,14 +84,30 @@ mountStack(el, {
|
|
|
77
84
|
});
|
|
78
85
|
```
|
|
79
86
|
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
87
|
+
For an image, the source is `{ kind: "media", media: img }` with an optional
|
|
88
|
+
`fit` of `"cover"` (default) or `"contain"`. `effects` is a list, bottom
|
|
89
|
+
layer first. `mountStack` returns the `mountGradient` handle plus
|
|
90
|
+
`setSource`, `setSourceParams`, `setEffects`, `setEffectParams(index, params)`,
|
|
91
|
+
`refreshMedia()` and `getGridInfo()`. `renderStackFrame` renders one frame to
|
|
92
|
+
a detached canvas and `createStackRenderer` is the seekable renderer for
|
|
93
|
+
video export, both with the same options.
|
|
94
|
+
|
|
95
|
+
Each effect's `params` array describes its controls the way `shader.params`
|
|
96
|
+
does, with four kinds: float, enum (a string value from `options`), bool and
|
|
97
|
+
colour (a `#rrggbb` string). A `when` field on a param says which other
|
|
98
|
+
param's value makes it relevant, for building UI. `effects` and
|
|
99
|
+
`getEffect(id)` expose the registry, and importing either pulls every effect.
|
|
100
|
+
|
|
101
|
+
Effect sizes are in pixels at 1080p, and each effect computes one value per
|
|
102
|
+
cell into a buffer that is the same at every output size, so a preview and a
|
|
103
|
+
4K export contain identical cells. The [repository
|
|
104
|
+
README](https://github.com/ugolbck/instantshader#effects) has images, every
|
|
105
|
+
param with its range, and the details of how preview and export line up.
|
|
83
106
|
|
|
84
107
|
## Seamless loops
|
|
85
108
|
|
|
86
109
|
Set `loopSeconds` and the animation repeats exactly, with no visible seam at
|
|
87
|
-
the wrap
|
|
110
|
+
the wrap. The frame at `t` and at `t + loopSeconds` are identical pixel for
|
|
88
111
|
pixel. Built for video export and for backgrounds that must not betray a
|
|
89
112
|
restart.
|
|
90
113
|
|
|
@@ -119,7 +142,7 @@ Notes:
|
|
|
119
142
|
light video file without slowing the animation down.
|
|
120
143
|
- **`flow` ties its travel speed to the loop length.** It animates by
|
|
121
144
|
translating in a straight line through a noise field that tiles, and it
|
|
122
|
-
covers exactly one tile per cycle
|
|
145
|
+
covers exactly one tile per cycle, so a short loop flows fast and a long
|
|
123
146
|
one flows slowly. The hand-tuned drift rate corresponds to a period around
|
|
124
147
|
60–90s; below ~30s the currents move noticeably faster than the look was
|
|
125
148
|
designed for. Compensate with `speed` rather than by shortening the loop.
|
|
@@ -130,9 +153,11 @@ Notes:
|
|
|
130
153
|
slow oscillations (petal breathing ~20s, fan lean ~30s, petal flex ~42s)
|
|
131
154
|
layered over a noise wander. Each oscillation holds still once the loop is
|
|
132
155
|
shorter than about half its own period, so below ~10s the wander is the only
|
|
133
|
-
thing left moving. `colorflow` is unaffected
|
|
156
|
+
thing left moving. `colorflow` is unaffected. It always fits at least one
|
|
134
157
|
full cycle into the loop, flowing faster on a short one.
|
|
135
|
-
- `halo`, `dune` and `whorl` always complete at least one full cycle of
|
|
136
|
-
main motion per loop, so a short loop simply runs them faster.
|
|
158
|
+
- `halo`, `dune` and `whorl` always complete at least one full cycle of
|
|
159
|
+
their main motion per loop, so a short loop simply runs them faster.
|
|
160
|
+
`burst` never turns; its rays stream outward one tile per loop. `glint`
|
|
161
|
+
travels one pattern period per loop, half a period under 12 s.
|
|
137
162
|
- Any loop necessarily revisits the same state every N seconds; a long period
|
|
138
163
|
is what buys the impression of never repeating.
|
package/dist/index.d.ts
CHANGED
|
@@ -340,6 +340,18 @@ declare const dune: ShaderDef;
|
|
|
340
340
|
//#region src/shaders/whorl.d.ts
|
|
341
341
|
declare const whorl: ShaderDef;
|
|
342
342
|
//#endregion
|
|
343
|
+
//#region src/shaders/silk.d.ts
|
|
344
|
+
declare const silk: ShaderDef;
|
|
345
|
+
//#endregion
|
|
346
|
+
//#region src/shaders/nacre.d.ts
|
|
347
|
+
declare const nacre: ShaderDef;
|
|
348
|
+
//#endregion
|
|
349
|
+
//#region src/shaders/burst.d.ts
|
|
350
|
+
declare const burst: ShaderDef;
|
|
351
|
+
//#endregion
|
|
352
|
+
//#region src/shaders/glint.d.ts
|
|
353
|
+
declare const glint: ShaderDef;
|
|
354
|
+
//#endregion
|
|
343
355
|
//#region src/effects/pixelate.d.ts
|
|
344
356
|
declare const pixelate: EffectDef;
|
|
345
357
|
//#endregion
|
|
@@ -473,4 +485,4 @@ declare function gridFor(width: number, height: number, cell: [number, number],
|
|
|
473
485
|
*/
|
|
474
486
|
declare function buildPaletteRamp(colors: string[]): Uint8Array;
|
|
475
487
|
//#endregion
|
|
476
|
-
export { type BoolParamDef, type ColorParamDef, type EffectDef, type EffectLayer, type EffectParamDef, type EffectTexture, type EnumParamDef, type FloatParamDef, type GeneratorDef, type Grid, type GridInfo, type MountHandle, type MountOptions, type ParamDef, type ParamValue, type RenderFrameResult, type Renderer, type RendererOptions, type ShaderDef, type Source, type StackHandle, type StackMountOptions, type StackOptions, type StackRenderer, type TextureData, type TextureEnv, ascii, beam, bloom, buildPaletteRamp, createRenderer, createStackRenderer, dither, dune, effects, flow, getEffect, getShader, gridFor, halftone, halo, mountGradient, mountStack, pixelate, renderGradientFrame, renderStackFrame, shaders, strata, whorl };
|
|
488
|
+
export { type BoolParamDef, type ColorParamDef, type EffectDef, type EffectLayer, type EffectParamDef, type EffectTexture, type EnumParamDef, type FloatParamDef, type GeneratorDef, type Grid, type GridInfo, type MountHandle, type MountOptions, type ParamDef, type ParamValue, type RenderFrameResult, type Renderer, type RendererOptions, type ShaderDef, type Source, type StackHandle, type StackMountOptions, type StackOptions, type StackRenderer, type TextureData, type TextureEnv, ascii, beam, bloom, buildPaletteRamp, burst, createRenderer, createStackRenderer, dither, dune, effects, flow, getEffect, getShader, glint, gridFor, halftone, halo, mountGradient, mountStack, nacre, pixelate, renderGradientFrame, renderStackFrame, shaders, silk, strata, whorl };
|
package/dist/index.js
CHANGED
|
@@ -254,7 +254,7 @@ vec2 seedOffset() {
|
|
|
254
254
|
|
|
255
255
|
//#endregion
|
|
256
256
|
//#region src/shaders/flow.ts
|
|
257
|
-
const FRAGMENT$
|
|
257
|
+
const FRAGMENT$10 = `
|
|
258
258
|
uniform float u_scale;
|
|
259
259
|
uniform float u_curl;
|
|
260
260
|
uniform float u_drift;
|
|
@@ -391,7 +391,7 @@ void main() {
|
|
|
391
391
|
const flow = {
|
|
392
392
|
id: "flow",
|
|
393
393
|
label: "Flow",
|
|
394
|
-
fragment: FRAGMENT$
|
|
394
|
+
fragment: FRAGMENT$10,
|
|
395
395
|
params: [
|
|
396
396
|
{
|
|
397
397
|
key: "scale",
|
|
@@ -447,7 +447,7 @@ const flow = {
|
|
|
447
447
|
|
|
448
448
|
//#endregion
|
|
449
449
|
//#region src/shaders/beam.ts
|
|
450
|
-
const FRAGMENT$
|
|
450
|
+
const FRAGMENT$9 = `
|
|
451
451
|
uniform float u_scale;
|
|
452
452
|
uniform float u_width;
|
|
453
453
|
uniform float u_glow;
|
|
@@ -701,7 +701,7 @@ void main() {
|
|
|
701
701
|
const beam = {
|
|
702
702
|
id: "beam",
|
|
703
703
|
label: "Beam",
|
|
704
|
-
fragment: FRAGMENT$
|
|
704
|
+
fragment: FRAGMENT$9,
|
|
705
705
|
params: [
|
|
706
706
|
{
|
|
707
707
|
key: "scale",
|
|
@@ -757,7 +757,7 @@ const beam = {
|
|
|
757
757
|
|
|
758
758
|
//#endregion
|
|
759
759
|
//#region src/shaders/bloom.ts
|
|
760
|
-
const FRAGMENT$
|
|
760
|
+
const FRAGMENT$8 = `
|
|
761
761
|
uniform float u_scale;
|
|
762
762
|
uniform float u_petals;
|
|
763
763
|
uniform float u_pinch;
|
|
@@ -916,7 +916,7 @@ void main() {
|
|
|
916
916
|
const bloom = {
|
|
917
917
|
id: "bloom",
|
|
918
918
|
label: "Bloom",
|
|
919
|
-
fragment: FRAGMENT$
|
|
919
|
+
fragment: FRAGMENT$8,
|
|
920
920
|
params: [
|
|
921
921
|
{
|
|
922
922
|
key: "scale",
|
|
@@ -990,7 +990,7 @@ const bloom = {
|
|
|
990
990
|
|
|
991
991
|
//#endregion
|
|
992
992
|
//#region src/shaders/halo.ts
|
|
993
|
-
const FRAGMENT$
|
|
993
|
+
const FRAGMENT$7 = `
|
|
994
994
|
uniform float u_radius;
|
|
995
995
|
uniform float u_x;
|
|
996
996
|
uniform float u_y;
|
|
@@ -1103,7 +1103,7 @@ void main() {
|
|
|
1103
1103
|
const halo = {
|
|
1104
1104
|
id: "halo",
|
|
1105
1105
|
label: "Halo",
|
|
1106
|
-
fragment: FRAGMENT$
|
|
1106
|
+
fragment: FRAGMENT$7,
|
|
1107
1107
|
params: [
|
|
1108
1108
|
{
|
|
1109
1109
|
key: "radius",
|
|
@@ -1178,7 +1178,7 @@ const halo = {
|
|
|
1178
1178
|
|
|
1179
1179
|
//#endregion
|
|
1180
1180
|
//#region src/shaders/strata.ts
|
|
1181
|
-
const FRAGMENT$
|
|
1181
|
+
const FRAGMENT$6 = `
|
|
1182
1182
|
uniform float u_scale;
|
|
1183
1183
|
uniform float u_layers;
|
|
1184
1184
|
uniform float u_warp;
|
|
@@ -1283,7 +1283,7 @@ void main() {
|
|
|
1283
1283
|
const strata = {
|
|
1284
1284
|
id: "strata",
|
|
1285
1285
|
label: "Strata",
|
|
1286
|
-
fragment: FRAGMENT$
|
|
1286
|
+
fragment: FRAGMENT$6,
|
|
1287
1287
|
params: [
|
|
1288
1288
|
{
|
|
1289
1289
|
key: "scale",
|
|
@@ -1375,7 +1375,7 @@ const strata = {
|
|
|
1375
1375
|
|
|
1376
1376
|
//#endregion
|
|
1377
1377
|
//#region src/shaders/dune.ts
|
|
1378
|
-
const FRAGMENT$
|
|
1378
|
+
const FRAGMENT$5 = `
|
|
1379
1379
|
uniform float u_layers;
|
|
1380
1380
|
uniform float u_swell;
|
|
1381
1381
|
uniform float u_waves;
|
|
@@ -1452,7 +1452,7 @@ void main() {
|
|
|
1452
1452
|
const dune = {
|
|
1453
1453
|
id: "dune",
|
|
1454
1454
|
label: "Dune",
|
|
1455
|
-
fragment: FRAGMENT$
|
|
1455
|
+
fragment: FRAGMENT$5,
|
|
1456
1456
|
params: [
|
|
1457
1457
|
{
|
|
1458
1458
|
key: "layers",
|
|
@@ -1526,7 +1526,7 @@ const dune = {
|
|
|
1526
1526
|
|
|
1527
1527
|
//#endregion
|
|
1528
1528
|
//#region src/shaders/whorl.ts
|
|
1529
|
-
const FRAGMENT = `
|
|
1529
|
+
const FRAGMENT$4 = `
|
|
1530
1530
|
uniform float u_blades;
|
|
1531
1531
|
uniform float u_twist;
|
|
1532
1532
|
uniform float u_depth;
|
|
@@ -1579,7 +1579,7 @@ void main() {
|
|
|
1579
1579
|
const whorl = {
|
|
1580
1580
|
id: "whorl",
|
|
1581
1581
|
label: "Whorl",
|
|
1582
|
-
fragment: FRAGMENT,
|
|
1582
|
+
fragment: FRAGMENT$4,
|
|
1583
1583
|
params: [
|
|
1584
1584
|
{
|
|
1585
1585
|
key: "blades",
|
|
@@ -1660,6 +1660,646 @@ const whorl = {
|
|
|
1660
1660
|
}
|
|
1661
1661
|
};
|
|
1662
1662
|
|
|
1663
|
+
//#endregion
|
|
1664
|
+
//#region src/shaders/silk.ts
|
|
1665
|
+
const FRAGMENT$3 = `
|
|
1666
|
+
uniform float u_scale;
|
|
1667
|
+
uniform float u_folds;
|
|
1668
|
+
uniform float u_depth;
|
|
1669
|
+
uniform float u_warp;
|
|
1670
|
+
uniform float u_sheen;
|
|
1671
|
+
uniform float u_light;
|
|
1672
|
+
uniform float u_grain;
|
|
1673
|
+
|
|
1674
|
+
${SIMPLEX_2D}
|
|
1675
|
+
${FBM}
|
|
1676
|
+
${SHAPE}
|
|
1677
|
+
${GRAIN}
|
|
1678
|
+
${ISO}
|
|
1679
|
+
${SEED}
|
|
1680
|
+
|
|
1681
|
+
const float PI = 3.14159265;
|
|
1682
|
+
|
|
1683
|
+
vec2 toField(vec2 v, vec2 axis) {
|
|
1684
|
+
return vec2(dot(v, axis) / (1.0 + 4.0 * u_folds), dot(v, vec2(-axis.y, axis.x)));
|
|
1685
|
+
}
|
|
1686
|
+
|
|
1687
|
+
// Fold height at frame point p. The warp is passed in, computed once at the
|
|
1688
|
+
// pixel: it varies over ~2 frame units, the taps are 0.006 apart.
|
|
1689
|
+
float height(vec2 p, vec2 axis, float freq, vec2 so, vec2 drift, float warp) {
|
|
1690
|
+
vec2 q = toField(p, axis) * freq + so + drift;
|
|
1691
|
+
q.y += warp;
|
|
1692
|
+
return fbm2(q);
|
|
1693
|
+
}
|
|
1694
|
+
|
|
1695
|
+
void main() {
|
|
1696
|
+
vec2 uv = worldUv();
|
|
1697
|
+
vec2 p = isoCoord(uv);
|
|
1698
|
+
|
|
1699
|
+
vec2 so = seedOffset();
|
|
1700
|
+
float axisAngle = seedHash(3.0) * PI;
|
|
1701
|
+
vec2 axis = vec2(cos(axisAngle), sin(axisAngle));
|
|
1702
|
+
float freq = 1.6 * u_scale;
|
|
1703
|
+
|
|
1704
|
+
vec2 drift = loopDrift(0.025, vec2(1.0, 0.0));
|
|
1705
|
+
// Warp: one coarse octave, shifts the across-fold coordinate so ridges
|
|
1706
|
+
// bend, converge and fork.
|
|
1707
|
+
float warp = u_warp * 1.4 * snoise(toField(p, axis) * (0.45 * freq) + so.yx + 31.0 + drift.yx);
|
|
1708
|
+
|
|
1709
|
+
float eps = 0.006;
|
|
1710
|
+
float hx1 = height(p + vec2(eps, 0.0), axis, freq, so, drift, warp);
|
|
1711
|
+
float hx0 = height(p - vec2(eps, 0.0), axis, freq, so, drift, warp);
|
|
1712
|
+
float hy1 = height(p + vec2(0.0, eps), axis, freq, so, drift, warp);
|
|
1713
|
+
float hy0 = height(p - vec2(0.0, eps), axis, freq, so, drift, warp);
|
|
1714
|
+
float h = 0.25 * (hx1 + hx0 + hy1 + hy0);
|
|
1715
|
+
|
|
1716
|
+
// Slope scale: fbm2 spans ~[-1, 1] over ~1/freq frame units, so its raw
|
|
1717
|
+
// gradient is O(freq); 0.35 * depth brings the default to slopes near 1.
|
|
1718
|
+
float amp = 0.35 * u_depth / eps;
|
|
1719
|
+
vec3 n = normalize(vec3(-(hx1 - hx0) * amp * 0.5, -(hy1 - hy0) * amp * 0.5, 1.0));
|
|
1720
|
+
|
|
1721
|
+
// Light: azimuth measured from the ACROSS-fold direction, so u_light = 0
|
|
1722
|
+
// always rakes across the folds whatever axis the seed picked (a light
|
|
1723
|
+
// along the folds shows no relief at all). Slow sway; elevation 40.
|
|
1724
|
+
float az = axisAngle + 0.5 * PI + u_light * PI / 180.0 + 0.14 * sin(loopFreq(0.12) * u_time + u_seed);
|
|
1725
|
+
vec3 L = vec3(cos(az) * 0.766, sin(az) * 0.766, 0.643);
|
|
1726
|
+
vec3 V = vec3(0.0, 0.0, 1.0);
|
|
1727
|
+
vec3 H = normalize(L + V);
|
|
1728
|
+
vec3 T = normalize(vec3(axis, 0.0) - n * dot(vec3(axis, 0.0), n));
|
|
1729
|
+
|
|
1730
|
+
float ndl = dot(n, L);
|
|
1731
|
+
float diff = 0.5 + 0.5 * ndl;
|
|
1732
|
+
float th = sqrt(max(1.0 - dot(T, H) * dot(T, H), 0.0));
|
|
1733
|
+
float sheen = (0.55 * pow(th, 48.0) + 0.3 * pow(th, 7.0)) * max(ndl, 0.0);
|
|
1734
|
+
// Valleys sit in shadow from the folds above them.
|
|
1735
|
+
float cav = 0.75 + 0.25 * (0.5 + 0.5 * h);
|
|
1736
|
+
|
|
1737
|
+
// Colour: its own coarse field, drifting on its own path.
|
|
1738
|
+
vec2 drift2 = loopDrift(0.02, vec2(0.0, 1.0));
|
|
1739
|
+
float t = spread(fbm2(p * (0.55 * u_scale) + so + 17.0 + drift2), 0.35);
|
|
1740
|
+
vec3 cloth = palette(t);
|
|
1741
|
+
|
|
1742
|
+
vec3 color = cloth * (0.35 + 0.65 * diff) * cav;
|
|
1743
|
+
color += mix(cloth, vec3(1.0), 0.5) * sheen * u_sheen;
|
|
1744
|
+
|
|
1745
|
+
float g = grain(uv, u_time) - 0.5;
|
|
1746
|
+
color += g * u_grain;
|
|
1747
|
+
|
|
1748
|
+
gl_FragColor = vec4(clamp(color, 0.0, 1.0), 1.0);
|
|
1749
|
+
}
|
|
1750
|
+
`;
|
|
1751
|
+
const silk = {
|
|
1752
|
+
id: "silk",
|
|
1753
|
+
label: "Silk",
|
|
1754
|
+
fragment: FRAGMENT$3,
|
|
1755
|
+
params: [
|
|
1756
|
+
{
|
|
1757
|
+
key: "scale",
|
|
1758
|
+
label: "Scale",
|
|
1759
|
+
min: .3,
|
|
1760
|
+
max: 2.5,
|
|
1761
|
+
step: .05,
|
|
1762
|
+
default: 1
|
|
1763
|
+
},
|
|
1764
|
+
{
|
|
1765
|
+
key: "folds",
|
|
1766
|
+
label: "Folds",
|
|
1767
|
+
min: 0,
|
|
1768
|
+
max: 1,
|
|
1769
|
+
step: .01,
|
|
1770
|
+
default: .6
|
|
1771
|
+
},
|
|
1772
|
+
{
|
|
1773
|
+
key: "depth",
|
|
1774
|
+
label: "Depth",
|
|
1775
|
+
min: .2,
|
|
1776
|
+
max: 2,
|
|
1777
|
+
step: .01,
|
|
1778
|
+
default: 1
|
|
1779
|
+
},
|
|
1780
|
+
{
|
|
1781
|
+
key: "warp",
|
|
1782
|
+
label: "Warp",
|
|
1783
|
+
min: 0,
|
|
1784
|
+
max: 1,
|
|
1785
|
+
step: .01,
|
|
1786
|
+
default: .5
|
|
1787
|
+
},
|
|
1788
|
+
{
|
|
1789
|
+
key: "sheen",
|
|
1790
|
+
label: "Sheen",
|
|
1791
|
+
min: 0,
|
|
1792
|
+
max: 1,
|
|
1793
|
+
step: .01,
|
|
1794
|
+
default: .6
|
|
1795
|
+
},
|
|
1796
|
+
{
|
|
1797
|
+
key: "light",
|
|
1798
|
+
label: "Light",
|
|
1799
|
+
min: 0,
|
|
1800
|
+
max: 360,
|
|
1801
|
+
step: 1,
|
|
1802
|
+
default: 20
|
|
1803
|
+
},
|
|
1804
|
+
{
|
|
1805
|
+
key: "grain",
|
|
1806
|
+
label: "Grain",
|
|
1807
|
+
min: 0,
|
|
1808
|
+
max: .5,
|
|
1809
|
+
step: .01,
|
|
1810
|
+
default: .06
|
|
1811
|
+
}
|
|
1812
|
+
],
|
|
1813
|
+
randomParams(rand) {
|
|
1814
|
+
return {
|
|
1815
|
+
scale: .7 + rand() * 1.1,
|
|
1816
|
+
folds: .3 + rand() * .7,
|
|
1817
|
+
depth: .6 + rand() * 1,
|
|
1818
|
+
warp: rand(),
|
|
1819
|
+
sheen: .3 + rand() * .6000000000000001,
|
|
1820
|
+
light: Math.floor((rand() < .5 ? 0 : 180) + (rand() - .5) * 100 + 360) % 360,
|
|
1821
|
+
grain: .06
|
|
1822
|
+
};
|
|
1823
|
+
}
|
|
1824
|
+
};
|
|
1825
|
+
|
|
1826
|
+
//#endregion
|
|
1827
|
+
//#region src/shaders/nacre.ts
|
|
1828
|
+
const FRAGMENT$2 = `
|
|
1829
|
+
uniform float u_scale;
|
|
1830
|
+
uniform float u_flow;
|
|
1831
|
+
uniform float u_crease;
|
|
1832
|
+
uniform float u_depth;
|
|
1833
|
+
uniform float u_iridescence;
|
|
1834
|
+
uniform float u_light;
|
|
1835
|
+
uniform float u_grain;
|
|
1836
|
+
|
|
1837
|
+
${SIMPLEX_2D}
|
|
1838
|
+
${FBM}
|
|
1839
|
+
${SHAPE}
|
|
1840
|
+
${GRAIN}
|
|
1841
|
+
${ISO}
|
|
1842
|
+
${SEED}
|
|
1843
|
+
|
|
1844
|
+
const float PI = 3.14159265;
|
|
1845
|
+
|
|
1846
|
+
float tri(float x) {
|
|
1847
|
+
return 1.0 - abs(1.0 - 2.0 * fract(0.5 * x));
|
|
1848
|
+
}
|
|
1849
|
+
|
|
1850
|
+
// One smooth octave with a faint second: pooled lobes, not texture. The
|
|
1851
|
+
// creases are narrow ridges where the base field crosses a level, so they
|
|
1852
|
+
// are contours of the lobes themselves: they hug each lobe's edge and, as
|
|
1853
|
+
// level sets of one field, never cross each other or cut through a lobe.
|
|
1854
|
+
float height(vec2 p, float f, vec2 so, vec2 drift, vec2 warp) {
|
|
1855
|
+
vec2 q = (p + warp) * f + so + drift;
|
|
1856
|
+
float base = snoise(q) + 0.18 * snoise(q * 2.1 + 5.0);
|
|
1857
|
+
float d0 = base;
|
|
1858
|
+
float d1 = abs(base) - 0.6;
|
|
1859
|
+
float crease = exp(-(d0 * d0) / 0.012) + 0.6 * exp(-(d1 * d1) / 0.01);
|
|
1860
|
+
return base * 0.7 + crease * u_crease * 0.3;
|
|
1861
|
+
}
|
|
1862
|
+
|
|
1863
|
+
void main() {
|
|
1864
|
+
vec2 uv = worldUv();
|
|
1865
|
+
vec2 p = isoCoord(uv);
|
|
1866
|
+
|
|
1867
|
+
vec2 so = seedOffset();
|
|
1868
|
+
float f = 0.55 * u_scale;
|
|
1869
|
+
vec2 drift = loopDrift(0.02, vec2(1.0, 0.0));
|
|
1870
|
+
|
|
1871
|
+
// One warp for every tap: it varies over ~2 frame units, the taps are
|
|
1872
|
+
// 0.006 apart.
|
|
1873
|
+
vec2 wq = p * (0.45 * f) + so.yx + 23.0 + drift.yx;
|
|
1874
|
+
vec2 warp = u_flow * 0.5 * vec2(snoise(wq), snoise(wq + vec2(9.2, 4.1)));
|
|
1875
|
+
|
|
1876
|
+
float eps = 0.006;
|
|
1877
|
+
float hx1 = height(p + vec2(eps, 0.0), f, so, drift, warp);
|
|
1878
|
+
float hx0 = height(p - vec2(eps, 0.0), f, so, drift, warp);
|
|
1879
|
+
float hy1 = height(p + vec2(0.0, eps), f, so, drift, warp);
|
|
1880
|
+
float hy0 = height(p - vec2(0.0, eps), f, so, drift, warp);
|
|
1881
|
+
|
|
1882
|
+
float amp = 0.5 * u_depth / eps;
|
|
1883
|
+
vec3 n = normalize(vec3(-(hx1 - hx0) * amp * 0.5, -(hy1 - hy0) * amp * 0.5, 1.0));
|
|
1884
|
+
float tilt = 1.0 - n.z;
|
|
1885
|
+
|
|
1886
|
+
float az = u_light * PI / 180.0 + 0.12 * sin(loopFreq(0.1) * u_time + u_seed);
|
|
1887
|
+
vec3 L = vec3(cos(az) * 0.643, sin(az) * 0.643, 0.766);
|
|
1888
|
+
float diff = 0.7 + 0.3 * dot(n, L);
|
|
1889
|
+
float rim = pow(tilt, 6.0) * 0.35;
|
|
1890
|
+
|
|
1891
|
+
vec2 drift2 = loopDrift(0.015, vec2(0.0, 1.0));
|
|
1892
|
+
float t0 = spread(fbm2(p * (0.4 * f) + so + 17.0 + drift2), 0.35);
|
|
1893
|
+
float t = tri(t0 + u_iridescence * 1.5 * tilt);
|
|
1894
|
+
vec3 color = palette(t) * diff + vec3(rim);
|
|
1895
|
+
|
|
1896
|
+
float g = grain(uv, u_time) - 0.5;
|
|
1897
|
+
color += g * u_grain;
|
|
1898
|
+
|
|
1899
|
+
gl_FragColor = vec4(clamp(color, 0.0, 1.0), 1.0);
|
|
1900
|
+
}
|
|
1901
|
+
`;
|
|
1902
|
+
const nacre = {
|
|
1903
|
+
id: "nacre",
|
|
1904
|
+
label: "Nacre",
|
|
1905
|
+
fragment: FRAGMENT$2,
|
|
1906
|
+
params: [
|
|
1907
|
+
{
|
|
1908
|
+
key: "scale",
|
|
1909
|
+
label: "Scale",
|
|
1910
|
+
min: .4,
|
|
1911
|
+
max: 2,
|
|
1912
|
+
step: .05,
|
|
1913
|
+
default: .9
|
|
1914
|
+
},
|
|
1915
|
+
{
|
|
1916
|
+
key: "flow",
|
|
1917
|
+
label: "Flow",
|
|
1918
|
+
min: 0,
|
|
1919
|
+
max: 1,
|
|
1920
|
+
step: .01,
|
|
1921
|
+
default: .5
|
|
1922
|
+
},
|
|
1923
|
+
{
|
|
1924
|
+
key: "crease",
|
|
1925
|
+
label: "Crease",
|
|
1926
|
+
min: 0,
|
|
1927
|
+
max: 1,
|
|
1928
|
+
step: .01,
|
|
1929
|
+
default: .6
|
|
1930
|
+
},
|
|
1931
|
+
{
|
|
1932
|
+
key: "depth",
|
|
1933
|
+
label: "Depth",
|
|
1934
|
+
min: .2,
|
|
1935
|
+
max: 2,
|
|
1936
|
+
step: .01,
|
|
1937
|
+
default: 1
|
|
1938
|
+
},
|
|
1939
|
+
{
|
|
1940
|
+
key: "iridescence",
|
|
1941
|
+
label: "Iridescence",
|
|
1942
|
+
min: 0,
|
|
1943
|
+
max: 1,
|
|
1944
|
+
step: .01,
|
|
1945
|
+
default: .6
|
|
1946
|
+
},
|
|
1947
|
+
{
|
|
1948
|
+
key: "light",
|
|
1949
|
+
label: "Light",
|
|
1950
|
+
min: 0,
|
|
1951
|
+
max: 360,
|
|
1952
|
+
step: 1,
|
|
1953
|
+
default: 40
|
|
1954
|
+
},
|
|
1955
|
+
{
|
|
1956
|
+
key: "grain",
|
|
1957
|
+
label: "Grain",
|
|
1958
|
+
min: 0,
|
|
1959
|
+
max: .3,
|
|
1960
|
+
step: .01,
|
|
1961
|
+
default: .04
|
|
1962
|
+
}
|
|
1963
|
+
],
|
|
1964
|
+
randomParams(rand) {
|
|
1965
|
+
return {
|
|
1966
|
+
scale: .5 + rand() * 1.1,
|
|
1967
|
+
flow: rand(),
|
|
1968
|
+
crease: .2 + rand() * .8,
|
|
1969
|
+
depth: .6 + rand() * 1,
|
|
1970
|
+
iridescence: .3 + rand() * .7,
|
|
1971
|
+
light: Math.floor(rand() * 360),
|
|
1972
|
+
grain: .04
|
|
1973
|
+
};
|
|
1974
|
+
}
|
|
1975
|
+
};
|
|
1976
|
+
|
|
1977
|
+
//#endregion
|
|
1978
|
+
//#region src/shaders/burst.ts
|
|
1979
|
+
const FRAGMENT$1 = `
|
|
1980
|
+
uniform float u_rays;
|
|
1981
|
+
uniform float u_sharp;
|
|
1982
|
+
uniform float u_glow;
|
|
1983
|
+
uniform float u_twist;
|
|
1984
|
+
uniform float u_x;
|
|
1985
|
+
uniform float u_y;
|
|
1986
|
+
uniform float u_grain;
|
|
1987
|
+
|
|
1988
|
+
${PERIODIC_2D}
|
|
1989
|
+
${GRAIN}
|
|
1990
|
+
${ISO}
|
|
1991
|
+
${SEED}
|
|
1992
|
+
|
|
1993
|
+
void main() {
|
|
1994
|
+
vec2 uv = worldUv();
|
|
1995
|
+
vec2 p = isoCoord(uv);
|
|
1996
|
+
vec2 halfIso = isoHalf();
|
|
1997
|
+
|
|
1998
|
+
vec2 c = vec2(u_x, u_y) * halfIso;
|
|
1999
|
+
vec2 rel = p - c;
|
|
2000
|
+
float r = max(length(rel), 0.0005);
|
|
2001
|
+
float theta = atan(rel.y, rel.x);
|
|
2002
|
+
float rho = log(r / 0.1) * 0.6;
|
|
2003
|
+
float th = theta + u_twist * 1.2 * rho;
|
|
2004
|
+
|
|
2005
|
+
// Ray count: the angular period of the noise, integral so the field
|
|
2006
|
+
// closes on itself around the centre.
|
|
2007
|
+
float A = floor(8.0 + 72.0 * u_rays);
|
|
2008
|
+
vec2 so = seedOffset();
|
|
2009
|
+
float flowOut = loopTravel(0.05, vec2(0.0, 1.0), 4.0).y;
|
|
2010
|
+
float flowPk = loopTravel(0.2, vec2(0.0, 1.0), 12.0).y;
|
|
2011
|
+
|
|
2012
|
+
vec2 sp = vec2(th / TAU * A, rho - flowOut + so.x);
|
|
2013
|
+
float rays = pnoise(sp, vec2(A, 4.0)) + 0.5 * pnoise(sp * 2.0 + vec2(0.0, so.y), vec2(2.0 * A, 8.0));
|
|
2014
|
+
// Packets: shorter along the ray and streaming out four times faster.
|
|
2015
|
+
float pk = pnoise(vec2(sp.x, rho * 3.0 - flowPk + so.y), vec2(A, 12.0));
|
|
2016
|
+
// Sector field: a few broad angular sectors that keep neighbouring rays
|
|
2017
|
+
// in one family, and the mask's contrast.
|
|
2018
|
+
float sector = pnoise(vec2(th / TAU * 6.0 + seedHash(3.0) * 6.0, 0.5), vec2(6.0, 1024.0));
|
|
2019
|
+
// Softer toward the centre, where the rays converge.
|
|
2020
|
+
float edge = mix(0.8, 0.2, u_sharp) + 0.4 * exp(-r / 0.3);
|
|
2021
|
+
float mask = smoothstep(-edge, edge, rays + 0.4 * pk + 0.3 * sector);
|
|
2022
|
+
|
|
2023
|
+
float hole = 1.0 - exp(-(r * r) / (0.25 * 0.25));
|
|
2024
|
+
float env = mix(hole, 1.0 + 0.6 * exp(-r / 0.35), u_glow) * exp(-0.3 * r);
|
|
2025
|
+
float hot = u_glow * exp(-(r * r) / (0.16 * 0.16));
|
|
2026
|
+
|
|
2027
|
+
float sway = 0.35 * sin(loopFreq(0.08) * u_time + u_seed);
|
|
2028
|
+
float theta0 = seedHash(2.0) * TAU + sway;
|
|
2029
|
+
float t = 0.5 + 0.5 * cos(th - theta0 + 2.0 * rays + 1.5 * sector);
|
|
2030
|
+
vec3 tint = palette(t);
|
|
2031
|
+
vec3 color = tint * (0.15 + 0.85 * mask * env);
|
|
2032
|
+
color = mix(color, vec3(1.0), hot * 0.85);
|
|
2033
|
+
|
|
2034
|
+
float g = grain(uv, u_time) - 0.5;
|
|
2035
|
+
color += g * u_grain;
|
|
2036
|
+
|
|
2037
|
+
gl_FragColor = vec4(clamp(color, 0.0, 1.0), 1.0);
|
|
2038
|
+
}
|
|
2039
|
+
`;
|
|
2040
|
+
const burst = {
|
|
2041
|
+
id: "burst",
|
|
2042
|
+
label: "Burst",
|
|
2043
|
+
fragment: FRAGMENT$1,
|
|
2044
|
+
params: [
|
|
2045
|
+
{
|
|
2046
|
+
key: "rays",
|
|
2047
|
+
label: "Rays",
|
|
2048
|
+
min: 0,
|
|
2049
|
+
max: 1,
|
|
2050
|
+
step: .01,
|
|
2051
|
+
default: .45
|
|
2052
|
+
},
|
|
2053
|
+
{
|
|
2054
|
+
key: "sharp",
|
|
2055
|
+
label: "Sharp",
|
|
2056
|
+
min: 0,
|
|
2057
|
+
max: 1,
|
|
2058
|
+
step: .01,
|
|
2059
|
+
default: .6
|
|
2060
|
+
},
|
|
2061
|
+
{
|
|
2062
|
+
key: "glow",
|
|
2063
|
+
label: "Glow",
|
|
2064
|
+
min: 0,
|
|
2065
|
+
max: 1,
|
|
2066
|
+
step: .01,
|
|
2067
|
+
default: .7
|
|
2068
|
+
},
|
|
2069
|
+
{
|
|
2070
|
+
key: "twist",
|
|
2071
|
+
label: "Twist",
|
|
2072
|
+
min: 0,
|
|
2073
|
+
max: 1,
|
|
2074
|
+
step: .01,
|
|
2075
|
+
default: .2
|
|
2076
|
+
},
|
|
2077
|
+
{
|
|
2078
|
+
key: "x",
|
|
2079
|
+
label: "X",
|
|
2080
|
+
min: -1,
|
|
2081
|
+
max: 1,
|
|
2082
|
+
step: .01,
|
|
2083
|
+
default: .1
|
|
2084
|
+
},
|
|
2085
|
+
{
|
|
2086
|
+
key: "y",
|
|
2087
|
+
label: "Y",
|
|
2088
|
+
min: -1,
|
|
2089
|
+
max: 1,
|
|
2090
|
+
step: .01,
|
|
2091
|
+
default: .05
|
|
2092
|
+
},
|
|
2093
|
+
{
|
|
2094
|
+
key: "grain",
|
|
2095
|
+
label: "Grain",
|
|
2096
|
+
min: 0,
|
|
2097
|
+
max: .3,
|
|
2098
|
+
step: .01,
|
|
2099
|
+
default: .14
|
|
2100
|
+
}
|
|
2101
|
+
],
|
|
2102
|
+
randomParams(rand) {
|
|
2103
|
+
return {
|
|
2104
|
+
rays: .2 + rand() * .7,
|
|
2105
|
+
sharp: .3 + rand() * .7,
|
|
2106
|
+
glow: .3 + rand() * .7,
|
|
2107
|
+
twist: rand() * .7,
|
|
2108
|
+
x: -.7 + rand() * 1.4,
|
|
2109
|
+
y: -.7 + rand() * 1.4,
|
|
2110
|
+
grain: .14
|
|
2111
|
+
};
|
|
2112
|
+
}
|
|
2113
|
+
};
|
|
2114
|
+
|
|
2115
|
+
//#endregion
|
|
2116
|
+
//#region src/shaders/glint.ts
|
|
2117
|
+
const FRAGMENT = `
|
|
2118
|
+
uniform float u_size;
|
|
2119
|
+
uniform float u_density;
|
|
2120
|
+
uniform float u_bend;
|
|
2121
|
+
uniform float u_angle;
|
|
2122
|
+
uniform float u_speed;
|
|
2123
|
+
uniform float u_grain;
|
|
2124
|
+
|
|
2125
|
+
${SIMPLEX_2D}
|
|
2126
|
+
${GRAIN}
|
|
2127
|
+
${ISO}
|
|
2128
|
+
${LOOP_ANGLE}
|
|
2129
|
+
${SEED}
|
|
2130
|
+
|
|
2131
|
+
const float PI = 3.14159265;
|
|
2132
|
+
const vec3 LUMA = vec3(0.2126, 0.7152, 0.0722);
|
|
2133
|
+
|
|
2134
|
+
float hash21(vec2 c) {
|
|
2135
|
+
return fract(sin(dot(c, vec2(127.1, 311.7)) + u_seed * 0.37) * 43758.5453);
|
|
2136
|
+
}
|
|
2137
|
+
|
|
2138
|
+
// Rhombus coverage at local offset d for half-extents a (along) and b
|
|
2139
|
+
// (across), edge ramped over aa.
|
|
2140
|
+
float rhombus(vec2 d, float a, float b, float aa) {
|
|
2141
|
+
float s = abs(d.x) / a + abs(d.y) / b - 1.0;
|
|
2142
|
+
return 1.0 - smoothstep(-aa, aa, s);
|
|
2143
|
+
}
|
|
2144
|
+
|
|
2145
|
+
void main() {
|
|
2146
|
+
vec2 uv = worldUv();
|
|
2147
|
+
vec2 p = isoCoord(uv);
|
|
2148
|
+
vec2 halfIso = isoHalf();
|
|
2149
|
+
float pixel = 2.0 * halfIso.y / u_resolution.y;
|
|
2150
|
+
|
|
2151
|
+
float ang = u_angle * PI / 180.0;
|
|
2152
|
+
vec2 q = vec2(p.x * cos(ang) + p.y * sin(ang), -p.x * sin(ang) + p.y * cos(ang));
|
|
2153
|
+
vec2 so = seedOffset();
|
|
2154
|
+
// The current: one slow bend, so the shoal arcs across the frame.
|
|
2155
|
+
float bend = 0.35 * u_bend * snoise(vec2(q.x * 0.9 + so.x, so.y));
|
|
2156
|
+
float across = q.y - bend;
|
|
2157
|
+
|
|
2158
|
+
// Background and haze.
|
|
2159
|
+
vec3 c0 = palette(0.0);
|
|
2160
|
+
vec3 c1 = palette(0.5);
|
|
2161
|
+
vec3 c2 = palette(1.0);
|
|
2162
|
+
float l0 = dot(c0, LUMA);
|
|
2163
|
+
float l1 = dot(c1, LUMA);
|
|
2164
|
+
float l2 = dot(c2, LUMA);
|
|
2165
|
+
vec3 dk = mix(c0, c1, step(l1, l0));
|
|
2166
|
+
dk = mix(dk, c2, step(l2, min(l0, l1)));
|
|
2167
|
+
vec3 color = dk * 0.1;
|
|
2168
|
+
color += palette(0.5) * 0.05 * exp(-(across * across) / 0.1);
|
|
2169
|
+
|
|
2170
|
+
float tw = loopFreq(1.2) * u_time;
|
|
2171
|
+
// Hash period along the stream, in cells. The lattice travels one period
|
|
2172
|
+
// per loop, so a short loop would race; halving the period halves that at
|
|
2173
|
+
// the cost of the pattern repeating every 8 cells instead of 16.
|
|
2174
|
+
float TILE = (u_loop > 0.0 && u_loop < 12.0) ? 8.0 : 16.0;
|
|
2175
|
+
|
|
2176
|
+
for (int layer = 0; layer < 3; layer++) {
|
|
2177
|
+
float fl = float(layer);
|
|
2178
|
+
float sizeMul = fl < 0.5 ? 0.5 : (fl < 1.5 ? 0.85 : 1.5);
|
|
2179
|
+
float speedMul = fl < 0.5 ? 0.5 : (fl < 1.5 ? 0.8 : 1.2);
|
|
2180
|
+
float bright = fl < 0.5 ? 0.45 : (fl < 1.5 ? 0.7 : 1.0);
|
|
2181
|
+
float soft = fl < 0.5 ? 2.5 : (fl < 1.5 ? 1.5 : 1.0);
|
|
2182
|
+
|
|
2183
|
+
float shard = u_size * sizeMul;
|
|
2184
|
+
float cs = shard * 3.2;
|
|
2185
|
+
// The static u_speed term gives the knob a visible effect at t = 0.
|
|
2186
|
+
float travel = loopTravel(0.08 * u_speed * speedMul, vec2(1.0, 0.0), cs * TILE).x + 0.3 * u_speed;
|
|
2187
|
+
vec2 l = vec2(q.x + travel, across) / cs;
|
|
2188
|
+
vec2 cell0 = floor(l);
|
|
2189
|
+
|
|
2190
|
+
for (int j = -1; j <= 1; j++) {
|
|
2191
|
+
for (int i = -1; i <= 1; i++) {
|
|
2192
|
+
vec2 cell = cell0 + vec2(float(i), float(j));
|
|
2193
|
+
vec2 key = vec2(mod(cell.x, TILE), cell.y + fl * 100.0);
|
|
2194
|
+
float h1 = hash21(key);
|
|
2195
|
+
float h2 = hash21(key + 7.0);
|
|
2196
|
+
float h3 = hash21(key + 19.0);
|
|
2197
|
+
float h4 = hash21(key + 31.0);
|
|
2198
|
+
float h5 = hash21(key + 47.0);
|
|
2199
|
+
|
|
2200
|
+
// Denser along the current, sparser off it.
|
|
2201
|
+
float rowY = (cell.y + 0.5) * cs;
|
|
2202
|
+
float present = step(h1, u_density * (0.12 + 0.88 * exp(-(rowY * rowY) / 0.05)));
|
|
2203
|
+
if (present < 0.5) continue;
|
|
2204
|
+
|
|
2205
|
+
vec2 centre = (cell + vec2(0.15 + 0.7 * h2, 0.15 + 0.7 * h3)) * cs;
|
|
2206
|
+
float sz = shard * (0.4 + 0.6 * h4);
|
|
2207
|
+
float dir = h5 < 0.5 ? -1.0 : 1.0;
|
|
2208
|
+
float ori = h5 * TAU + dir * loopAngle(0.25 + 0.5 * h4);
|
|
2209
|
+
float ca = cos(ori);
|
|
2210
|
+
float sa = sin(ori);
|
|
2211
|
+
|
|
2212
|
+
vec2 d = vec2(l.x * cs, across) - centre;
|
|
2213
|
+
vec2 dl = vec2(d.x * ca + d.y * sa, -d.x * sa + d.y * ca);
|
|
2214
|
+
float aa = pixel * soft / sz;
|
|
2215
|
+
float fr = 0.08 * sz;
|
|
2216
|
+
float covR = rhombus(vec2((d.x - fr) * ca + d.y * sa, -(d.x - fr) * sa + d.y * ca) / sz, 1.0, 0.35, aa);
|
|
2217
|
+
float covG = rhombus(dl / sz, 1.0, 0.35, aa);
|
|
2218
|
+
float covB = rhombus(vec2((d.x + fr) * ca + d.y * sa, -(d.x + fr) * sa + d.y * ca) / sz, 1.0, 0.35, aa);
|
|
2219
|
+
|
|
2220
|
+
float twinkle = 0.5 + 0.5 * sin(tw + h2 * TAU + ori * 2.0);
|
|
2221
|
+
float flash = twinkle * twinkle * twinkle;
|
|
2222
|
+
vec3 col = palette(fract(h3 + 0.13 * fl));
|
|
2223
|
+
float lum = dot(col, LUMA);
|
|
2224
|
+
col = col * (1.0 + 2.0 * (1.0 - lum) * (1.0 - lum)) * (0.5 + 0.5 * twinkle) + vec3(0.6) * flash;
|
|
2225
|
+
col *= bright;
|
|
2226
|
+
color += vec3(covR, covG, covB) * col;
|
|
2227
|
+
}
|
|
2228
|
+
}
|
|
2229
|
+
}
|
|
2230
|
+
|
|
2231
|
+
float g = grain(uv, u_time) - 0.5;
|
|
2232
|
+
color += g * u_grain;
|
|
2233
|
+
|
|
2234
|
+
gl_FragColor = vec4(clamp(color, 0.0, 1.0), 1.0);
|
|
2235
|
+
}
|
|
2236
|
+
`;
|
|
2237
|
+
const glint = {
|
|
2238
|
+
id: "glint",
|
|
2239
|
+
label: "Glint",
|
|
2240
|
+
fragment: FRAGMENT,
|
|
2241
|
+
params: [
|
|
2242
|
+
{
|
|
2243
|
+
key: "size",
|
|
2244
|
+
label: "Size",
|
|
2245
|
+
min: .01,
|
|
2246
|
+
max: .06,
|
|
2247
|
+
step: .001,
|
|
2248
|
+
default: .03
|
|
2249
|
+
},
|
|
2250
|
+
{
|
|
2251
|
+
key: "density",
|
|
2252
|
+
label: "Density",
|
|
2253
|
+
min: .2,
|
|
2254
|
+
max: 1,
|
|
2255
|
+
step: .01,
|
|
2256
|
+
default: .6
|
|
2257
|
+
},
|
|
2258
|
+
{
|
|
2259
|
+
key: "bend",
|
|
2260
|
+
label: "Bend",
|
|
2261
|
+
min: 0,
|
|
2262
|
+
max: 1,
|
|
2263
|
+
step: .01,
|
|
2264
|
+
default: .5
|
|
2265
|
+
},
|
|
2266
|
+
{
|
|
2267
|
+
key: "angle",
|
|
2268
|
+
label: "Angle",
|
|
2269
|
+
min: 0,
|
|
2270
|
+
max: 360,
|
|
2271
|
+
step: 1,
|
|
2272
|
+
default: 10
|
|
2273
|
+
},
|
|
2274
|
+
{
|
|
2275
|
+
key: "speed",
|
|
2276
|
+
label: "Speed",
|
|
2277
|
+
min: .3,
|
|
2278
|
+
max: 2,
|
|
2279
|
+
step: .01,
|
|
2280
|
+
default: 1
|
|
2281
|
+
},
|
|
2282
|
+
{
|
|
2283
|
+
key: "grain",
|
|
2284
|
+
label: "Grain",
|
|
2285
|
+
min: 0,
|
|
2286
|
+
max: .3,
|
|
2287
|
+
step: .01,
|
|
2288
|
+
default: .06
|
|
2289
|
+
}
|
|
2290
|
+
],
|
|
2291
|
+
randomParams(rand) {
|
|
2292
|
+
return {
|
|
2293
|
+
size: .015 + rand() * .03,
|
|
2294
|
+
density: .4 + rand() * .6,
|
|
2295
|
+
bend: rand(),
|
|
2296
|
+
angle: Math.floor(rand() * 360),
|
|
2297
|
+
speed: .6 + rand() * 1,
|
|
2298
|
+
grain: .06
|
|
2299
|
+
};
|
|
2300
|
+
}
|
|
2301
|
+
};
|
|
2302
|
+
|
|
1663
2303
|
//#endregion
|
|
1664
2304
|
//#region src/effects/pixelate.ts
|
|
1665
2305
|
const CELL_FRAGMENT$3 = `
|
|
@@ -1913,6 +2553,13 @@ void main() {
|
|
|
1913
2553
|
* over another effect, there is no ramp coordinate to recover and tone stays
|
|
1914
2554
|
* luma (a gradient map).
|
|
1915
2555
|
*
|
|
2556
|
+
* paletteStop() snaps a tone to the nearest of the palette's stops
|
|
2557
|
+
* (u_paletteStops is the stop count). Halftone and ASCII use it in palette
|
|
2558
|
+
* mode: they do not quantize tone the way Dither's `levels` does, so
|
|
2559
|
+
* without the snap, palette mode over a generator handed back the exact
|
|
2560
|
+
* source color and looked identical to source mode. Snapped, each cell is
|
|
2561
|
+
* one of the palette's own colors, flat.
|
|
2562
|
+
*
|
|
1916
2563
|
* The search is 33 coarse + 17 fine ramp samples. That is affordable
|
|
1917
2564
|
* because tone is evaluated per cell or per lattice point, not per pixel.
|
|
1918
2565
|
* The ends snap to exactly 0 and 1: generators clamp their coordinate, so
|
|
@@ -1925,6 +2572,7 @@ uniform vec3 u_ink;
|
|
|
1925
2572
|
uniform vec3 u_paper;
|
|
1926
2573
|
uniform float u_invert;
|
|
1927
2574
|
uniform float u_sourceIsRamp; // 1 when this layer reads a generator directly
|
|
2575
|
+
uniform float u_paletteStops; // number of colors in the palette
|
|
1928
2576
|
float rampPosition(vec3 c) {
|
|
1929
2577
|
float best = 0.0;
|
|
1930
2578
|
float bd = 1e9;
|
|
@@ -1950,6 +2598,10 @@ float toneOf(vec3 c) {
|
|
|
1950
2598
|
float t = toneIsRamp() ? rampPosition(c) : luma(c);
|
|
1951
2599
|
return u_invert > 0.5 ? 1.0 - t : t;
|
|
1952
2600
|
}
|
|
2601
|
+
vec3 paletteStop(float tone) {
|
|
2602
|
+
float n = max(u_paletteStops - 1.0, 1.0);
|
|
2603
|
+
return palette(floor(tone * n + 0.5) / n);
|
|
2604
|
+
}
|
|
1953
2605
|
vec3 colorize(float tone, vec3 src) {
|
|
1954
2606
|
if (u_colorMode < 0.5) return src;
|
|
1955
2607
|
if (u_colorMode < 1.5) return mix(u_ink, u_paper, tone);
|
|
@@ -2228,9 +2880,11 @@ void main() {
|
|
|
2228
2880
|
|
|
2229
2881
|
// Ink color. Duotone inks every shape with u_ink (colorize() would mix
|
|
2230
2882
|
// toward paper by tone, which is dither's meaning of duotone). Palette
|
|
2231
|
-
//
|
|
2883
|
+
// inks each dot with the nearest palette STOP to the un-inverted tone, so
|
|
2884
|
+
// Invert flips sizes and leaves colors, and the dots are flat palette
|
|
2885
|
+
// colors rather than a copy of the source.
|
|
2232
2886
|
vec3 color = sc;
|
|
2233
|
-
if (u_colorMode > 1.5) color =
|
|
2887
|
+
if (u_colorMode > 1.5) color = paletteStop(toneIsRamp() ? rampPosition(sc) : luma(sc));
|
|
2234
2888
|
else if (u_colorMode > 0.5) color = u_ink;
|
|
2235
2889
|
|
|
2236
2890
|
gl_FragColor = vec4(color, ink);
|
|
@@ -2401,7 +3055,7 @@ const halftone = {
|
|
|
2401
3055
|
min: 6,
|
|
2402
3056
|
max: 160,
|
|
2403
3057
|
step: .5,
|
|
2404
|
-
default:
|
|
3058
|
+
default: 10
|
|
2405
3059
|
},
|
|
2406
3060
|
{
|
|
2407
3061
|
key: "angle",
|
|
@@ -2417,7 +3071,7 @@ const halftone = {
|
|
|
2417
3071
|
min: .2,
|
|
2418
3072
|
max: 1.5,
|
|
2419
3073
|
step: .01,
|
|
2420
|
-
default: 1
|
|
3074
|
+
default: 1.4
|
|
2421
3075
|
},
|
|
2422
3076
|
{
|
|
2423
3077
|
key: "softness",
|
|
@@ -2425,7 +3079,7 @@ const halftone = {
|
|
|
2425
3079
|
min: 0,
|
|
2426
3080
|
max: 1,
|
|
2427
3081
|
step: .01,
|
|
2428
|
-
default:
|
|
3082
|
+
default: .1
|
|
2429
3083
|
},
|
|
2430
3084
|
{
|
|
2431
3085
|
key: "contrast",
|
|
@@ -2433,7 +3087,7 @@ const halftone = {
|
|
|
2433
3087
|
min: 0,
|
|
2434
3088
|
max: 2,
|
|
2435
3089
|
step: .01,
|
|
2436
|
-
default: 1
|
|
3090
|
+
default: 1.15
|
|
2437
3091
|
},
|
|
2438
3092
|
{
|
|
2439
3093
|
key: "pulse",
|
|
@@ -2444,7 +3098,7 @@ const halftone = {
|
|
|
2444
3098
|
default: 0
|
|
2445
3099
|
},
|
|
2446
3100
|
...colorModeParams({
|
|
2447
|
-
mode: "
|
|
3101
|
+
mode: "palette",
|
|
2448
3102
|
paperAlways: true
|
|
2449
3103
|
})
|
|
2450
3104
|
],
|
|
@@ -2463,11 +3117,11 @@ const halftone = {
|
|
|
2463
3117
|
return {
|
|
2464
3118
|
grid: rand() < .5 ? "square" : "hex",
|
|
2465
3119
|
shape: shapes[Math.floor(rand() * shapes.length)],
|
|
2466
|
-
size: Math.round(
|
|
3120
|
+
size: Math.round(8 + rand() * 30),
|
|
2467
3121
|
angle: Math.round(rand() * 180),
|
|
2468
|
-
radius: .
|
|
2469
|
-
softness: rand() < .7 ?
|
|
2470
|
-
contrast: 1,
|
|
3122
|
+
radius: 1.2 + rand() * .3,
|
|
3123
|
+
softness: rand() < .7 ? .1 : rand() * .5,
|
|
3124
|
+
contrast: 1.15,
|
|
2471
3125
|
pulse: 0,
|
|
2472
3126
|
colorMode: modes[Math.floor(rand() * modes.length)],
|
|
2473
3127
|
ink: "#111111",
|
|
@@ -2745,7 +3399,8 @@ void main() {
|
|
|
2745
3399
|
} else if (u_colorMode < 1.5) {
|
|
2746
3400
|
color = u_ink;
|
|
2747
3401
|
} else {
|
|
2748
|
-
|
|
3402
|
+
// Nearest palette stop, flat: see paletteStop() in chunks.ts.
|
|
3403
|
+
color = paletteStop(toneIsRamp() ? rampPosition(sc) : luma(sc));
|
|
2749
3404
|
}
|
|
2750
3405
|
|
|
2751
3406
|
gl_FragColor = vec4(color, glyph / 255.0);
|
|
@@ -2927,7 +3582,11 @@ const shaders = [
|
|
|
2927
3582
|
halo,
|
|
2928
3583
|
strata,
|
|
2929
3584
|
dune,
|
|
2930
|
-
whorl
|
|
3585
|
+
whorl,
|
|
3586
|
+
silk,
|
|
3587
|
+
nacre,
|
|
3588
|
+
burst,
|
|
3589
|
+
glint
|
|
2931
3590
|
];
|
|
2932
3591
|
function getShader(id) {
|
|
2933
3592
|
return shaders.find((s) => s.id === id);
|
|
@@ -3941,6 +4600,7 @@ function createStackRenderer(opts) {
|
|
|
3941
4600
|
function applyEffectUniforms(p, state, grid, overGenerator) {
|
|
3942
4601
|
const ref = refSize(canvas.width, canvas.height);
|
|
3943
4602
|
gl.uniform1f(p.loc("u_sourceIsRamp"), overGenerator ? 1 : 0);
|
|
4603
|
+
gl.uniform1f(p.loc("u_paletteStops"), colors.length);
|
|
3944
4604
|
gl.uniform2f(p.loc("u_refSize"), ref[0], ref[1]);
|
|
3945
4605
|
gl.uniform1f(p.loc("u_outputScale"), outputScale(canvas.width, canvas.height));
|
|
3946
4606
|
if (grid) {
|
|
@@ -4364,4 +5024,4 @@ function createRenderer(opts) {
|
|
|
4364
5024
|
}
|
|
4365
5025
|
|
|
4366
5026
|
//#endregion
|
|
4367
|
-
export { ascii, beam, bloom, buildPaletteRamp, createRenderer, createStackRenderer, dither, dune, effects, flow, getEffect, getShader, gridFor, halftone, halo, mountGradient, mountStack, pixelate, renderGradientFrame, renderStackFrame, shaders, strata, whorl };
|
|
5027
|
+
export { ascii, beam, bloom, buildPaletteRamp, burst, createRenderer, createStackRenderer, dither, dune, effects, flow, getEffect, getShader, glint, gridFor, halftone, halo, mountGradient, mountStack, nacre, pixelate, renderGradientFrame, renderStackFrame, shaders, silk, strata, whorl };
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "instantshader",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "Animated WebGL gradient shaders. Zero dependencies.",
|
|
3
|
+
"version": "0.7.0",
|
|
4
|
+
"description": "Animated WebGL gradient shaders, plus dither, pixelate, halftone and ASCII effects. Zero dependencies.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"repository": {
|
|
@@ -33,7 +33,11 @@
|
|
|
33
33
|
"gradient",
|
|
34
34
|
"mesh-gradient",
|
|
35
35
|
"animated-gradient",
|
|
36
|
-
"background"
|
|
36
|
+
"background",
|
|
37
|
+
"dither",
|
|
38
|
+
"halftone",
|
|
39
|
+
"pixelate",
|
|
40
|
+
"ascii"
|
|
37
41
|
],
|
|
38
42
|
"scripts": {
|
|
39
43
|
"build": "tsdown",
|