@brochington/shader-backgrounds 0.1.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/.github/workflows/deploy-demo-to-pages.yml +63 -0
- package/PLUGINS.md +269 -0
- package/README.md +159 -0
- package/demo.js +1044 -0
- package/index.html +194 -0
- package/package.json +23 -0
- package/src/index.ts +5 -0
- package/src/lib/components/web-component.ts +198 -0
- package/src/lib/core/ShaderCanvas.ts +235 -0
- package/src/lib/core/types.ts +26 -0
- package/src/lib/plugins/AuroraWavesPlugin.ts +128 -0
- package/src/lib/plugins/CausticsPlugin.ts +128 -0
- package/src/lib/plugins/ContourLinesPlugin.ts +148 -0
- package/src/lib/plugins/DreamyBokehPlugin.ts +191 -0
- package/src/lib/plugins/GradientPlugin.ts +445 -0
- package/src/lib/plugins/GrainyFogPlugin.ts +139 -0
- package/src/lib/plugins/InkWashPlugin.ts +182 -0
- package/src/lib/plugins/LiquidOrbPlugin.ts +140 -0
- package/src/lib/plugins/RetroGridPlugin.ts +77 -0
- package/src/lib/plugins/SoftStarfieldPlugin.ts +156 -0
- package/src/lib/plugins/StainedGlassPlugin.ts +261 -0
- package/src/lib/plugins/index.ts +11 -0
- package/tsconfig.json +26 -0
- package/vite.config.ts +19 -0
- package/vite.demo.config.ts +13 -0
|
@@ -0,0 +1,261 @@
|
|
|
1
|
+
import { Color } from 'ogl';
|
|
2
|
+
import { ShaderPlugin } from '../core/types';
|
|
3
|
+
|
|
4
|
+
export type StainedGlassConfig = {
|
|
5
|
+
/** Background behind the glass (shows through a bit) */
|
|
6
|
+
backgroundColor: string;
|
|
7
|
+
/** Lead/edge color */
|
|
8
|
+
leadColor?: string; // default "#0b0b10"
|
|
9
|
+
|
|
10
|
+
/** Palette colors for glass cells */
|
|
11
|
+
colorA?: string; // default "#38bdf8"
|
|
12
|
+
colorB?: string; // default "#a78bfa"
|
|
13
|
+
colorC?: string; // default "#fb7185"
|
|
14
|
+
colorD?: string; // default "#fbbf24"
|
|
15
|
+
|
|
16
|
+
/** Cell scale */
|
|
17
|
+
scale?: number; // default 3.2
|
|
18
|
+
/**
|
|
19
|
+
* Pattern variant (changes the underlying coordinate transform).
|
|
20
|
+
* - 0: classic
|
|
21
|
+
* - 1: crystal (anisotropic)
|
|
22
|
+
* - 2: radial-ish twist
|
|
23
|
+
*/
|
|
24
|
+
variant?: 0 | 1 | 2; // default 0
|
|
25
|
+
/** Random seed (any number). Change this to get a different layout. */
|
|
26
|
+
seed?: number; // default 0
|
|
27
|
+
/**
|
|
28
|
+
* Site jitter 0..1
|
|
29
|
+
* - 0 => very regular cells
|
|
30
|
+
* - 1 => fully random Voronoi sites
|
|
31
|
+
*/
|
|
32
|
+
jitter?: number; // default 1.0
|
|
33
|
+
/** Rotate the pattern in radians */
|
|
34
|
+
rotation?: number; // default 0
|
|
35
|
+
/** Edge thickness */
|
|
36
|
+
edgeWidth?: number; // default 0.08
|
|
37
|
+
/** Edge sharpness (higher = crisper lines) */
|
|
38
|
+
edgeSharpness?: number; // default 1.25
|
|
39
|
+
/** Glow along edges */
|
|
40
|
+
edgeGlow?: number; // default 0.45
|
|
41
|
+
/** Warp amount (0..1.5) */
|
|
42
|
+
distortion?: number; // default 0.55
|
|
43
|
+
/** Motion speed */
|
|
44
|
+
speed?: number; // default 0.12
|
|
45
|
+
/** Grain */
|
|
46
|
+
grainAmount?: number; // default 0.02
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
export class StainedGlassPlugin implements ShaderPlugin {
|
|
50
|
+
name = 'stained-glass';
|
|
51
|
+
|
|
52
|
+
fragmentShader = /* glsl */ `
|
|
53
|
+
precision highp float;
|
|
54
|
+
#ifdef GL_OES_standard_derivatives
|
|
55
|
+
#extension GL_OES_standard_derivatives : enable
|
|
56
|
+
#endif
|
|
57
|
+
|
|
58
|
+
uniform float uTimeInternal;
|
|
59
|
+
uniform vec2 uResolution;
|
|
60
|
+
uniform vec3 uBg;
|
|
61
|
+
uniform vec3 uLead;
|
|
62
|
+
uniform vec3 uA;
|
|
63
|
+
uniform vec3 uB;
|
|
64
|
+
uniform vec3 uC;
|
|
65
|
+
uniform vec3 uD;
|
|
66
|
+
uniform float uScale;
|
|
67
|
+
uniform float uSeed;
|
|
68
|
+
uniform float uJitter;
|
|
69
|
+
uniform float uRotate;
|
|
70
|
+
uniform int uVariant;
|
|
71
|
+
uniform float uEdgeW;
|
|
72
|
+
uniform float uEdgeSharp;
|
|
73
|
+
uniform float uGlow;
|
|
74
|
+
uniform float uDist;
|
|
75
|
+
uniform float uGrain;
|
|
76
|
+
|
|
77
|
+
varying vec2 vUv;
|
|
78
|
+
|
|
79
|
+
float hash12(vec2 p) {
|
|
80
|
+
vec3 p3 = fract(vec3(p.xyx) * 0.1031);
|
|
81
|
+
p3 += dot(p3, p3.yzx + 33.33);
|
|
82
|
+
return fract((p3.x + p3.y) * p3.z);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
vec2 hash22(vec2 p) {
|
|
86
|
+
float n = hash12(p);
|
|
87
|
+
return vec2(n, hash12(p + n + 19.19));
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
float noise(vec2 p) {
|
|
91
|
+
vec2 i = floor(p);
|
|
92
|
+
vec2 f = fract(p);
|
|
93
|
+
float a = hash12(i);
|
|
94
|
+
float b = hash12(i + vec2(1.0, 0.0));
|
|
95
|
+
float c = hash12(i + vec2(0.0, 1.0));
|
|
96
|
+
float d = hash12(i + vec2(1.0, 1.0));
|
|
97
|
+
vec2 u = f * f * (3.0 - 2.0 * f);
|
|
98
|
+
return mix(a, b, u.x) + (c - a) * u.y * (1.0 - u.x) + (d - b) * u.x * u.y;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
vec3 palette4(float h) {
|
|
102
|
+
// Blend 4 colors in a loop-friendly way.
|
|
103
|
+
vec3 ab = mix(uA, uB, smoothstep(0.0, 0.50, h));
|
|
104
|
+
vec3 cd = mix(uC, uD, smoothstep(0.50, 1.0, h));
|
|
105
|
+
return mix(ab, cd, smoothstep(0.25, 0.85, h));
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
mat2 rot2(float a) {
|
|
109
|
+
float s = sin(a), c = cos(a);
|
|
110
|
+
return mat2(c, -s, s, c);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
// Returns:
|
|
114
|
+
// x: distance to nearest site
|
|
115
|
+
// y: border metric (small near borders)
|
|
116
|
+
// z: random id
|
|
117
|
+
vec3 voronoi(vec2 x) {
|
|
118
|
+
vec2 n = floor(x);
|
|
119
|
+
vec2 f = fract(x);
|
|
120
|
+
|
|
121
|
+
float md = 8.0;
|
|
122
|
+
float md2 = 8.0;
|
|
123
|
+
vec2 mr = vec2(0.0);
|
|
124
|
+
vec2 seed2 = vec2(uSeed, uSeed * 1.618);
|
|
125
|
+
|
|
126
|
+
for (int j = -1; j <= 1; j++) {
|
|
127
|
+
for (int i = -1; i <= 1; i++) {
|
|
128
|
+
vec2 g = vec2(float(i), float(j));
|
|
129
|
+
vec2 o = hash22(n + g + seed2);
|
|
130
|
+
// Jitter controls how "random" the site is inside the cell.
|
|
131
|
+
o = mix(vec2(0.5), o, clamp(uJitter, 0.0, 1.0));
|
|
132
|
+
vec2 r = g + o - f;
|
|
133
|
+
float d = dot(r, r);
|
|
134
|
+
if (d < md) {
|
|
135
|
+
md2 = md;
|
|
136
|
+
md = d;
|
|
137
|
+
mr = n + g + o;
|
|
138
|
+
} else if (d < md2) {
|
|
139
|
+
md2 = d;
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
float d1 = sqrt(md);
|
|
145
|
+
float d2 = sqrt(md2);
|
|
146
|
+
float border = d2 - d1; // small at edges
|
|
147
|
+
return vec3(d1, border, hash12(mr + seed2));
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
void main() {
|
|
151
|
+
float aspect = uResolution.x / uResolution.y;
|
|
152
|
+
vec2 uv = vUv;
|
|
153
|
+
vec2 p = (uv - 0.5) * vec2(aspect, 1.0);
|
|
154
|
+
float t = uTimeInternal;
|
|
155
|
+
|
|
156
|
+
// Subtle low-frequency warp to avoid static mosaic vibe
|
|
157
|
+
vec2 warp = vec2(
|
|
158
|
+
noise(p * 1.5 + vec2(0.07 * t, -0.03 * t)) - 0.5,
|
|
159
|
+
noise(p * 1.5 + vec2(-0.05 * t, 0.06 * t) + 19.19) - 0.5
|
|
160
|
+
);
|
|
161
|
+
p += warp * (0.30 * uDist);
|
|
162
|
+
|
|
163
|
+
// Variant transforms (changes the cell character)
|
|
164
|
+
vec2 g = p;
|
|
165
|
+
g = rot2(uRotate) * g;
|
|
166
|
+
if (uVariant == 1) {
|
|
167
|
+
// Crystal: anisotropic scaling for more "shard-like" cells
|
|
168
|
+
g *= mat2(1.35, 0.35, -0.10, 0.85);
|
|
169
|
+
} else if (uVariant == 2) {
|
|
170
|
+
// Radial-ish twist: mild angular warp
|
|
171
|
+
float ang = atan(g.y, g.x);
|
|
172
|
+
float rad = length(g);
|
|
173
|
+
g += 0.15 * vec2(cos(ang * 3.0 + rad * 2.0), sin(ang * 2.0 - rad * 2.4));
|
|
174
|
+
}
|
|
175
|
+
g *= uScale;
|
|
176
|
+
vec3 v = voronoi(g);
|
|
177
|
+
|
|
178
|
+
float border = v.y;
|
|
179
|
+
float id = v.z;
|
|
180
|
+
|
|
181
|
+
// Lead line mask (1 at borders)
|
|
182
|
+
float w = max(0.0005, uEdgeW);
|
|
183
|
+
float aa = 0.0015;
|
|
184
|
+
#ifdef GL_OES_standard_derivatives
|
|
185
|
+
aa = fwidth(border) / max(0.0001, uEdgeSharp);
|
|
186
|
+
#endif
|
|
187
|
+
float lead = 1.0 - smoothstep(w - aa, w + aa, border);
|
|
188
|
+
|
|
189
|
+
// Cell color from palette + gentle variation
|
|
190
|
+
vec3 cell = palette4(id);
|
|
191
|
+
float tint = (noise(g * 0.85 + id * 11.7) - 0.5) * 0.18;
|
|
192
|
+
cell *= (1.0 + tint);
|
|
193
|
+
|
|
194
|
+
// Faux “glass thickness” / caustic-y highlight
|
|
195
|
+
float highlight = smoothstep(0.02, 0.30, noise(g * 2.2 + vec2(0.0, t * 0.6)));
|
|
196
|
+
highlight *= (1.0 - lead);
|
|
197
|
+
|
|
198
|
+
// Edge glow
|
|
199
|
+
float glow = exp(-border * border / max(0.00001, (w * w) * 0.35));
|
|
200
|
+
glow *= uGlow;
|
|
201
|
+
|
|
202
|
+
// Compose
|
|
203
|
+
vec3 col = mix(uBg, cell, 0.92);
|
|
204
|
+
col += cell * highlight * 0.10;
|
|
205
|
+
|
|
206
|
+
// Lead overrides + glow on top
|
|
207
|
+
col = mix(col, uLead, lead);
|
|
208
|
+
col += (cell * 0.55 + vec3(1.0) * 0.25) * glow;
|
|
209
|
+
|
|
210
|
+
// Subtle vignette
|
|
211
|
+
float vig = 1.0 - smoothstep(0.35, 1.15, length(p * vec2(1.0, 0.95)));
|
|
212
|
+
col *= 0.90 + 0.10 * vig;
|
|
213
|
+
|
|
214
|
+
// Grain
|
|
215
|
+
float gr = (hash12(uv * uResolution + t * 61.0) - 0.5) * 2.0;
|
|
216
|
+
col += gr * uGrain;
|
|
217
|
+
|
|
218
|
+
gl_FragColor = vec4(clamp(col, 0.0, 1.0), 1.0);
|
|
219
|
+
}
|
|
220
|
+
`;
|
|
221
|
+
|
|
222
|
+
uniforms: any;
|
|
223
|
+
private speed: number;
|
|
224
|
+
|
|
225
|
+
constructor(config: StainedGlassConfig) {
|
|
226
|
+
const bg = new Color(config.backgroundColor);
|
|
227
|
+
const lead = new Color(config.leadColor ?? '#0b0b10');
|
|
228
|
+
const a = new Color(config.colorA ?? '#38bdf8');
|
|
229
|
+
const b = new Color(config.colorB ?? '#a78bfa');
|
|
230
|
+
const c = new Color(config.colorC ?? '#fb7185');
|
|
231
|
+
const d = new Color(config.colorD ?? '#fbbf24');
|
|
232
|
+
|
|
233
|
+
this.speed = config.speed ?? 0.12;
|
|
234
|
+
|
|
235
|
+
this.uniforms = {
|
|
236
|
+
uBg: { value: [bg.r, bg.g, bg.b] },
|
|
237
|
+
uLead: { value: [lead.r, lead.g, lead.b] },
|
|
238
|
+
uA: { value: [a.r, a.g, a.b] },
|
|
239
|
+
uB: { value: [b.r, b.g, b.b] },
|
|
240
|
+
uC: { value: [c.r, c.g, c.b] },
|
|
241
|
+
uD: { value: [d.r, d.g, d.b] },
|
|
242
|
+
uScale: { value: config.scale ?? 3.2 },
|
|
243
|
+
uSeed: { value: config.seed ?? 0 },
|
|
244
|
+
uJitter: { value: config.jitter ?? 1.0 },
|
|
245
|
+
uRotate: { value: config.rotation ?? 0 },
|
|
246
|
+
uVariant: { value: config.variant ?? 0 },
|
|
247
|
+
uEdgeW: { value: config.edgeWidth ?? 0.08 },
|
|
248
|
+
uEdgeSharp: { value: config.edgeSharpness ?? 1.25 },
|
|
249
|
+
uGlow: { value: config.edgeGlow ?? 0.45 },
|
|
250
|
+
uDist: { value: config.distortion ?? 0.55 },
|
|
251
|
+
uGrain: { value: config.grainAmount ?? 0.02 },
|
|
252
|
+
uTimeInternal: { value: 0 },
|
|
253
|
+
};
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
onRender(dt: number) {
|
|
257
|
+
this.uniforms.uTimeInternal.value += dt * 0.001 * this.speed;
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export * from './GradientPlugin';
|
|
2
|
+
export * from './GrainyFogPlugin';
|
|
3
|
+
export * from './RetroGridPlugin';
|
|
4
|
+
export * from './LiquidOrbPlugin';
|
|
5
|
+
export * from './CausticsPlugin';
|
|
6
|
+
export * from './AuroraWavesPlugin';
|
|
7
|
+
export * from './SoftStarfieldPlugin';
|
|
8
|
+
export * from './ContourLinesPlugin';
|
|
9
|
+
export * from './DreamyBokehPlugin';
|
|
10
|
+
export * from './InkWashPlugin';
|
|
11
|
+
export * from './StainedGlassPlugin';
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2020",
|
|
4
|
+
"module": "ESNext",
|
|
5
|
+
"lib": ["ES2020", "DOM", "WebWorker"],
|
|
6
|
+
"declaration": true,
|
|
7
|
+
"outDir": "./dist",
|
|
8
|
+
"strict": true,
|
|
9
|
+
"esModuleInterop": true,
|
|
10
|
+
"skipLibCheck": true,
|
|
11
|
+
"forceConsistentCasingInFileNames": true,
|
|
12
|
+
"moduleResolution": "bundler",
|
|
13
|
+
"allowImportingTsExtensions": false,
|
|
14
|
+
"resolveJsonModule": true,
|
|
15
|
+
"isolatedModules": true,
|
|
16
|
+
"noEmit": false,
|
|
17
|
+
"types": ["vite/client"]
|
|
18
|
+
},
|
|
19
|
+
"include": [
|
|
20
|
+
"src/**/*"
|
|
21
|
+
],
|
|
22
|
+
"exclude": [
|
|
23
|
+
"node_modules",
|
|
24
|
+
"dist"
|
|
25
|
+
]
|
|
26
|
+
}
|
package/vite.config.ts
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { defineConfig } from 'vite';
|
|
2
|
+
import dts from 'vite-plugin-dts';
|
|
3
|
+
import { resolve } from 'path';
|
|
4
|
+
|
|
5
|
+
export default defineConfig({
|
|
6
|
+
build: {
|
|
7
|
+
lib: {
|
|
8
|
+
entry: resolve(__dirname, 'src/index.ts'),
|
|
9
|
+
name: 'ShaderBackgrounds',
|
|
10
|
+
fileName: 'shader-backgrounds',
|
|
11
|
+
},
|
|
12
|
+
rollupOptions: {
|
|
13
|
+
// Ensure we don't bundle OGL if we want the user to bring their own,
|
|
14
|
+
// but for a standalone generic lib, bundling it is usually safer/easier for the user.
|
|
15
|
+
// We will bundle it here for "zero config" usage.
|
|
16
|
+
},
|
|
17
|
+
},
|
|
18
|
+
plugins: [dts()],
|
|
19
|
+
});
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { defineConfig } from 'vite';
|
|
2
|
+
|
|
3
|
+
// Build the repo-root `index.html` as a static demo site (for GitHub Pages).
|
|
4
|
+
// Set BASE_PATH in CI to `/<repo-name>/` so asset URLs work under Pages subpaths.
|
|
5
|
+
export default defineConfig({
|
|
6
|
+
base: process.env.BASE_PATH ?? '/',
|
|
7
|
+
build: {
|
|
8
|
+
outDir: 'dist-demo',
|
|
9
|
+
emptyOutDir: true,
|
|
10
|
+
},
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
|