instantshader 0.2.0 → 0.4.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/dist/index.d.ts +4 -1
- package/dist/index.js +280 -22
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -123,6 +123,9 @@ declare const flow: ShaderDef;
|
|
|
123
123
|
//#region src/shaders/beam.d.ts
|
|
124
124
|
declare const beam: ShaderDef;
|
|
125
125
|
//#endregion
|
|
126
|
+
//#region src/shaders/bloom.d.ts
|
|
127
|
+
declare const bloom: ShaderDef;
|
|
128
|
+
//#endregion
|
|
126
129
|
//#region src/registry.d.ts
|
|
127
130
|
declare const shaders: readonly ShaderDef[];
|
|
128
131
|
declare function getShader(id: string): ShaderDef | undefined;
|
|
@@ -188,4 +191,4 @@ declare function renderGradientFrame(opts: {
|
|
|
188
191
|
*/
|
|
189
192
|
declare function buildPaletteRamp(colors: string[]): Uint8Array;
|
|
190
193
|
//#endregion
|
|
191
|
-
export { type MountHandle, type MountOptions, type ParamDef, type RenderFrameResult, type Renderer, type RendererOptions, type ShaderDef, beam, buildPaletteRamp, createRenderer, flow, getShader, mountGradient, renderGradientFrame, shaders };
|
|
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 };
|
package/dist/index.js
CHANGED
|
@@ -190,8 +190,9 @@ float grain(vec2 uv, float time) {
|
|
|
190
190
|
|
|
191
191
|
//#endregion
|
|
192
192
|
//#region src/shaders/flow.ts
|
|
193
|
-
const FRAGMENT$
|
|
193
|
+
const FRAGMENT$2 = `
|
|
194
194
|
uniform float u_scale;
|
|
195
|
+
uniform float u_curl;
|
|
195
196
|
uniform float u_drift;
|
|
196
197
|
uniform float u_openness;
|
|
197
198
|
uniform float u_grain;
|
|
@@ -236,11 +237,22 @@ void main() {
|
|
|
236
237
|
// composition reorganized every ~3 seconds, measured as more pixel change
|
|
237
238
|
// over 3.5s than the beam prototype showed over 7.5s.
|
|
238
239
|
//
|
|
239
|
-
//
|
|
240
|
-
//
|
|
241
|
-
//
|
|
242
|
-
//
|
|
243
|
-
|
|
240
|
+
// Curl field frequency, relative to the fbm's. Below 1.0 the currents are
|
|
241
|
+
// LARGER than the colour masses they carry, which is the look: sampled at
|
|
242
|
+
// the same frequency each mass sits inside its own little eddy, the
|
|
243
|
+
// advection only roughens mass edges, and the result is indistinguishable
|
|
244
|
+
// from a plain warped fbm.
|
|
245
|
+
//
|
|
246
|
+
// u_curl replaces what was a hardcoded 0.55, and its default is 1.05
|
|
247
|
+
// because the potential is pnoise now. Classic Perlin's lattice is a unit
|
|
248
|
+
// grid while simplex's skewed cells are roughly 0.7 units, so the same
|
|
249
|
+
// input scale yields visibly coarser features -- fewer closed eddies. 1.05
|
|
250
|
+
// was matched by eye against a reference render of the pre-pnoise look.
|
|
251
|
+
//
|
|
252
|
+
// The visible frame spans curlScale units of noise, so the tile has to be
|
|
253
|
+
// at least twice that or the field repeats inside a single frame, which
|
|
254
|
+
// looks like wallpaper; ceil keeps it integral, which pnoise requires.
|
|
255
|
+
float curlScale = u_scale * u_curl;
|
|
244
256
|
float tile = max(2.0, ceil(curlScale * 2.0));
|
|
245
257
|
|
|
246
258
|
// Straight-line travel through a tiling field: the direction never changes,
|
|
@@ -264,18 +276,18 @@ void main() {
|
|
|
264
276
|
// the NUMBER of steps that turns advection into rotation: one step is a
|
|
265
277
|
// plain directional shove, and at two the point still travels an almost
|
|
266
278
|
// straight chord. The third is where it curves enough to close visible
|
|
267
|
-
// eddies, which is the whole point of the look.
|
|
268
|
-
// 0.08 to 0.055 to keep the total travel about where it was.
|
|
279
|
+
// eddies, which is the whole point of the look.
|
|
269
280
|
//
|
|
270
|
-
//
|
|
271
|
-
//
|
|
272
|
-
//
|
|
273
|
-
//
|
|
274
|
-
//
|
|
281
|
+
// Step gain 0.19, up from the 0.055 that was tuned against a simplex
|
|
282
|
+
// potential. pnoise carries shallower gradients, so the old gain advected
|
|
283
|
+
// the point far too little and the eddies stopped closing -- the frame went
|
|
284
|
+
// to soft diagonal bands. The gain absorbs that difference rather than the
|
|
285
|
+
// default of u_drift, which stays at 0.5 in its published 0-1 range so the
|
|
286
|
+
// knob means the same thing it always did.
|
|
275
287
|
vec2 advected = uv;
|
|
276
|
-
advected += curl(advected * curlScale + u_seed + drift, tile) * u_drift * 0.
|
|
277
|
-
advected += curl(advected * curlScale + u_seed + drift, tile) * u_drift * 0.
|
|
278
|
-
advected += curl(advected * curlScale + u_seed + drift, tile) * u_drift * 0.
|
|
288
|
+
advected += curl(advected * curlScale + u_seed + drift, tile) * u_drift * 0.19;
|
|
289
|
+
advected += curl(advected * curlScale + u_seed + drift, tile) * u_drift * 0.19;
|
|
290
|
+
advected += curl(advected * curlScale + u_seed + drift, tile) * u_drift * 0.19;
|
|
279
291
|
|
|
280
292
|
float t = fbm2(advected * u_scale + u_seed);
|
|
281
293
|
|
|
@@ -315,7 +327,7 @@ void main() {
|
|
|
315
327
|
const flow = {
|
|
316
328
|
id: "flow",
|
|
317
329
|
label: "Flow",
|
|
318
|
-
fragment: FRAGMENT$
|
|
330
|
+
fragment: FRAGMENT$2,
|
|
319
331
|
params: [
|
|
320
332
|
{
|
|
321
333
|
key: "scale",
|
|
@@ -325,6 +337,14 @@ const flow = {
|
|
|
325
337
|
step: .05,
|
|
326
338
|
default: 1.7
|
|
327
339
|
},
|
|
340
|
+
{
|
|
341
|
+
key: "curl",
|
|
342
|
+
label: "Curl",
|
|
343
|
+
min: .3,
|
|
344
|
+
max: 1.6,
|
|
345
|
+
step: .05,
|
|
346
|
+
default: 1.05
|
|
347
|
+
},
|
|
328
348
|
{
|
|
329
349
|
key: "drift",
|
|
330
350
|
label: "Drift",
|
|
@@ -353,7 +373,8 @@ const flow = {
|
|
|
353
373
|
randomParams(rand) {
|
|
354
374
|
return {
|
|
355
375
|
scale: .6 + rand() * 2,
|
|
356
|
-
|
|
376
|
+
curl: .6 + rand() * .7000000000000001,
|
|
377
|
+
drift: .25 + rand() * .75,
|
|
357
378
|
openness: rand() * 1,
|
|
358
379
|
grain: .08
|
|
359
380
|
};
|
|
@@ -362,7 +383,7 @@ const flow = {
|
|
|
362
383
|
|
|
363
384
|
//#endregion
|
|
364
385
|
//#region src/shaders/beam.ts
|
|
365
|
-
const FRAGMENT = `
|
|
386
|
+
const FRAGMENT$1 = `
|
|
366
387
|
uniform float u_scale;
|
|
367
388
|
uniform float u_width;
|
|
368
389
|
uniform float u_glow;
|
|
@@ -616,7 +637,7 @@ void main() {
|
|
|
616
637
|
const beam = {
|
|
617
638
|
id: "beam",
|
|
618
639
|
label: "Beam",
|
|
619
|
-
fragment: FRAGMENT,
|
|
640
|
+
fragment: FRAGMENT$1,
|
|
620
641
|
params: [
|
|
621
642
|
{
|
|
622
643
|
key: "scale",
|
|
@@ -670,9 +691,246 @@ const beam = {
|
|
|
670
691
|
}
|
|
671
692
|
};
|
|
672
693
|
|
|
694
|
+
//#endregion
|
|
695
|
+
//#region src/shaders/bloom.ts
|
|
696
|
+
const FRAGMENT = `
|
|
697
|
+
uniform float u_scale;
|
|
698
|
+
uniform float u_petals;
|
|
699
|
+
uniform float u_pinch;
|
|
700
|
+
uniform float u_bend;
|
|
701
|
+
uniform float u_sway;
|
|
702
|
+
uniform float u_colorflow;
|
|
703
|
+
uniform float u_grain;
|
|
704
|
+
|
|
705
|
+
${SIMPLEX_2D}
|
|
706
|
+
${GRAIN}
|
|
707
|
+
|
|
708
|
+
const float PI = 3.14159265;
|
|
709
|
+
|
|
710
|
+
// Triangle-wave ping-pong: period 2, range [0,1], IDENTITY on [0,1] when the
|
|
711
|
+
// phase is zero -- so colorflow=off renders the plain radial ramp, and any
|
|
712
|
+
// moving phase slides color bands through the pattern with no fract() seam
|
|
713
|
+
// anywhere (the wave reflects instead of jumping).
|
|
714
|
+
float tri(float x) {
|
|
715
|
+
return 1.0 - abs(1.0 - 2.0 * fract(0.5 * x));
|
|
716
|
+
}
|
|
717
|
+
|
|
718
|
+
void main() {
|
|
719
|
+
vec2 uv = worldUv();
|
|
720
|
+
|
|
721
|
+
// Isotropic frame, same construction as beam: worldUv() is 0-1 on both
|
|
722
|
+
// axes of a 16:9 world, so raw uv would render every petal 1.78x wider
|
|
723
|
+
// than tall and the fan would smear sideways. Scaling x by the world
|
|
724
|
+
// aspect makes a unit circle a screen circle; halfIso is the frame's
|
|
725
|
+
// visible half-extents in that space (cover-fit aware), used to place the
|
|
726
|
+
// origin against the actual frame edges at any canvas aspect.
|
|
727
|
+
float worldAspect = 1000.0 / 562.5;
|
|
728
|
+
float canvasAspect = u_resolution.x / u_resolution.y;
|
|
729
|
+
vec2 iso = (uv - 0.5) * vec2(worldAspect, 1.0);
|
|
730
|
+
vec2 halfIso = vec2(0.5 * min(1.0, canvasAspect / worldAspect),
|
|
731
|
+
0.5 * min(1.0, worldAspect / canvasAspect))
|
|
732
|
+
* vec2(worldAspect, 1.0);
|
|
733
|
+
|
|
734
|
+
// ---- per-instance composition, all derived from u_seed ----------------
|
|
735
|
+
float seedRow = u_seed * 0.61 + 7.0;
|
|
736
|
+
|
|
737
|
+
// Origin: anywhere along the bottom edge (references use bottom-left and
|
|
738
|
+
// bottom-center), from slightly inside the frame (the hot core peeks in,
|
|
739
|
+
// as in all three references) to a bit below it.
|
|
740
|
+
float ox = snoise(vec2(seedRow, 1.3)) * 0.8 * halfIso.x;
|
|
741
|
+
// At or just below the edge -- never inside: an origin inside the frame
|
|
742
|
+
// shows petals radiating in every direction (a starburst), while the
|
|
743
|
+
// references always crop the fan at its base.
|
|
744
|
+
float oy = -halfIso.y * (1.02 + 0.11 * (1.0 + snoise(vec2(seedRow, 9.1))));
|
|
745
|
+
vec2 origin = vec2(ox, oy);
|
|
746
|
+
|
|
747
|
+
// Fan rotation. The rose envelope has k lobes evenly spaced around the
|
|
748
|
+
// full circle, so any rotation leaves several pointing into the frame;
|
|
749
|
+
// this just varies WHICH part of the fan the frame crops.
|
|
750
|
+
float theta0 = snoise(vec2(seedRow, 5.2)) * PI;
|
|
751
|
+
|
|
752
|
+
vec2 rel = iso - origin;
|
|
753
|
+
float r = length(rel);
|
|
754
|
+
float theta = atan(rel.y, rel.x);
|
|
755
|
+
|
|
756
|
+
// ---- sway: the shapes move ---------------------------------------------
|
|
757
|
+
// Lean: the whole fan pivots a few degrees around the origin. Shear pulse:
|
|
758
|
+
// the bend term below oscillates, so petals flex along their length rather
|
|
759
|
+
// than rotating rigidly. Both sinusoidal through loopFreq, so they are
|
|
760
|
+
// exactly periodic when looping (and freeze, rather than speed up, when
|
|
761
|
+
// the loop is too short for their tuned rates -- see loopFreq).
|
|
762
|
+
// The sines alone are not enough: loopFreq freezes them at loops shorter
|
|
763
|
+
// than ~half their period (its documented anti-throb choice), which left
|
|
764
|
+
// sway with NO motion at all at 4-8s loops. wdrift is the non-freezing
|
|
765
|
+
// half -- a loopDrift walk through the per-petal noise (below) and the
|
|
766
|
+
// lean, exactly periodic at ANY loop length by construction, same as the
|
|
767
|
+
// siblings' primary motion.
|
|
768
|
+
vec2 wdrift = loopDrift(0.05 * u_sway, vec2(1.0, 0.0));
|
|
769
|
+
float lean = u_sway * (0.06 * sin(loopFreq(0.21) * u_time + u_seed)
|
|
770
|
+
+ 0.05 * snoise(vec2(seedRow * 0.47, 9.3) + wdrift));
|
|
771
|
+
float shearPulse = u_sway * 0.08 * sin(loopFreq(0.15) * u_time + 2.3 + u_seed);
|
|
772
|
+
|
|
773
|
+
// Bend: angular shear proportional to r curves each petal progressively
|
|
774
|
+
// toward its tip -- the gentle bow the reference petals have -- instead of
|
|
775
|
+
// rotating the fan rigidly.
|
|
776
|
+
float th = theta - theta0 - lean + (u_bend + shearPulse) * r;
|
|
777
|
+
|
|
778
|
+
// ---- rose-curve envelope ------------------------------------------------
|
|
779
|
+
// k is snapped to an integer: |cos| has period pi, so integer k makes the
|
|
780
|
+
// envelope exactly 2pi-periodic and the atan branch cut at theta = +-pi is
|
|
781
|
+
// invisible. A fractional k would draw a hard radial seam there.
|
|
782
|
+
float k = floor(u_petals + 0.5);
|
|
783
|
+
float a = 0.5 * k * th;
|
|
784
|
+
float e = pow(abs(cos(a)), u_pinch);
|
|
785
|
+
|
|
786
|
+
// Per-petal identity: which lobe this pixel belongs to, expressed as the
|
|
787
|
+
// lobe's center ANGLE and hashed through cos/sin so it is periodic around
|
|
788
|
+
// the circle -- a raw lobe index would jump by k across the branch cut and
|
|
789
|
+
// tear the per-petal variation along that ray. The discontinuity between
|
|
790
|
+
// ADJACENT lobes is harmless: it sits exactly in the crease, where e ~ 0
|
|
791
|
+
// pushes both sides to the background color anyway.
|
|
792
|
+
float lobe = floor(a / PI + 0.5);
|
|
793
|
+
float cAngle = theta0 + 2.0 * PI * lobe / k;
|
|
794
|
+
float perLobe = 0.28 * snoise(vec2(cos(cAngle), sin(cAngle)) * 1.9
|
|
795
|
+
+ vec2(seedRow * 0.13, seedRow * 0.29) + wdrift);
|
|
796
|
+
|
|
797
|
+
// Breathing: each petal's length swells ~10%, phase-offset around the fan
|
|
798
|
+
// by 2*cAngle (integer multiple of the angle, so it survives the branch
|
|
799
|
+
// cut) -- the petals ripple in sequence instead of pulsing in lockstep.
|
|
800
|
+
float breathe = u_sway * 0.10 * sin(loopFreq(0.32) * u_time + 2.0 * cAngle + u_seed * 0.7);
|
|
801
|
+
float len = 1.0 + perLobe + breathe;
|
|
802
|
+
|
|
803
|
+
// ---- the field ----------------------------------------------------------
|
|
804
|
+
// eps = 0.075 is the crease floor (see header). R = 1.4 at scale 1 puts
|
|
805
|
+
// the default tips just past the frame's top edge with the origin at the
|
|
806
|
+
// bottom, matching the references' crop.
|
|
807
|
+
float R = 1.4 * u_scale;
|
|
808
|
+
float t = r / (R * len * (e + 0.075));
|
|
809
|
+
|
|
810
|
+
// Radial shaping: pow < 1 compresses the ramp's early stops into a small
|
|
811
|
+
// hot core at the origin and hands most of each petal's length to the
|
|
812
|
+
// later stops -- in the references the petals are dominated by ONE body
|
|
813
|
+
// color (the second-to-last stop) for ~70% of their length, with the core
|
|
814
|
+
// colors confined to the base. Linear t spread the early stops across half
|
|
815
|
+
// the petal and the body color only appeared at the rim.
|
|
816
|
+
t = pow(t, 0.5);
|
|
817
|
+
|
|
818
|
+
// ---- colorflow: the colors move ----------------------------------------
|
|
819
|
+
// Phase in tri-units (period 2 = one full out-and-back palette cycle).
|
|
820
|
+
// Not looping: linear crawl; the +37 base offset means the knob has a
|
|
821
|
+
// visible effect even at t=0 (and 37 is deliberately not a multiple of the
|
|
822
|
+
// period). Looping: exactly n cycles per loop, floored at ONE -- unlike
|
|
823
|
+
// the sway sines, colorflow is a headline motion, and freezing it at
|
|
824
|
+
// common loop lengths (loopFreq's choice) would read as the feature being
|
|
825
|
+
// broken rather than as restraint. One cycle over a short loop is simply a
|
|
826
|
+
// faster flow, which is what a short loop asks for.
|
|
827
|
+
float pRate = 0.05 * u_colorflow;
|
|
828
|
+
float p;
|
|
829
|
+
if (u_loop <= 0.0) {
|
|
830
|
+
p = pRate * (u_time + 37.0);
|
|
831
|
+
} else {
|
|
832
|
+
p = 2.0 * max(1.0, floor(pRate * u_loop * 0.5 + 0.5)) * (u_time / u_loop);
|
|
833
|
+
}
|
|
834
|
+
|
|
835
|
+
// The flow lives INSIDE the silhouette: the mask fades it out across the
|
|
836
|
+
// tips so the background (t >= 1) stays pinned to the last stop and the
|
|
837
|
+
// negative space never pulses. Gated on u_colorflow so 0 is exactly the
|
|
838
|
+
// static field even while looping (where p above moves regardless).
|
|
839
|
+
float flowMix = (1.0 - smoothstep(0.82, 1.0, t)) * smoothstep(0.0, 0.08, u_colorflow);
|
|
840
|
+
float tc = mix(min(t, 1.0), tri(t - p), flowMix);
|
|
841
|
+
|
|
842
|
+
vec3 color = palette(tc);
|
|
843
|
+
|
|
844
|
+
// Grain: cheap per-pixel dither, centered at 0 so it can darken or
|
|
845
|
+
// lighten symmetrically instead of just brightening the whole frame.
|
|
846
|
+
float g = grain(uv, u_time) - 0.5;
|
|
847
|
+
color += g * u_grain;
|
|
848
|
+
|
|
849
|
+
gl_FragColor = vec4(clamp(color, 0.0, 1.0), 1.0);
|
|
850
|
+
}
|
|
851
|
+
`;
|
|
852
|
+
const bloom = {
|
|
853
|
+
id: "bloom",
|
|
854
|
+
label: "Bloom",
|
|
855
|
+
fragment: FRAGMENT,
|
|
856
|
+
params: [
|
|
857
|
+
{
|
|
858
|
+
key: "scale",
|
|
859
|
+
label: "Scale",
|
|
860
|
+
min: .5,
|
|
861
|
+
max: 2,
|
|
862
|
+
step: .05,
|
|
863
|
+
default: .9
|
|
864
|
+
},
|
|
865
|
+
{
|
|
866
|
+
key: "petals",
|
|
867
|
+
label: "Petals",
|
|
868
|
+
min: 6,
|
|
869
|
+
max: 16,
|
|
870
|
+
step: 1,
|
|
871
|
+
default: 11
|
|
872
|
+
},
|
|
873
|
+
{
|
|
874
|
+
key: "pinch",
|
|
875
|
+
label: "Pinch",
|
|
876
|
+
min: .35,
|
|
877
|
+
max: 2.5,
|
|
878
|
+
step: .05,
|
|
879
|
+
default: .6
|
|
880
|
+
},
|
|
881
|
+
{
|
|
882
|
+
key: "bend",
|
|
883
|
+
label: "Bend",
|
|
884
|
+
min: -.9,
|
|
885
|
+
max: .9,
|
|
886
|
+
step: .05,
|
|
887
|
+
default: .25
|
|
888
|
+
},
|
|
889
|
+
{
|
|
890
|
+
key: "sway",
|
|
891
|
+
label: "Sway",
|
|
892
|
+
min: 0,
|
|
893
|
+
max: 1,
|
|
894
|
+
step: .01,
|
|
895
|
+
default: .5
|
|
896
|
+
},
|
|
897
|
+
{
|
|
898
|
+
key: "colorflow",
|
|
899
|
+
label: "Color flow",
|
|
900
|
+
min: 0,
|
|
901
|
+
max: 1,
|
|
902
|
+
step: .01,
|
|
903
|
+
default: 0
|
|
904
|
+
},
|
|
905
|
+
{
|
|
906
|
+
key: "grain",
|
|
907
|
+
label: "Grain",
|
|
908
|
+
min: 0,
|
|
909
|
+
max: .3,
|
|
910
|
+
step: .01,
|
|
911
|
+
default: .08
|
|
912
|
+
}
|
|
913
|
+
],
|
|
914
|
+
randomParams(rand) {
|
|
915
|
+
return {
|
|
916
|
+
scale: .7 + rand() * .9000000000000001,
|
|
917
|
+
petals: Math.floor(8 + rand() * 7),
|
|
918
|
+
pinch: .5 + rand() * 1.1,
|
|
919
|
+
bend: -.6 + rand() * 1.2,
|
|
920
|
+
sway: .2 + rand() * .7,
|
|
921
|
+
colorflow: rand() * .8,
|
|
922
|
+
grain: .08
|
|
923
|
+
};
|
|
924
|
+
}
|
|
925
|
+
};
|
|
926
|
+
|
|
673
927
|
//#endregion
|
|
674
928
|
//#region src/registry.ts
|
|
675
|
-
const shaders = [
|
|
929
|
+
const shaders = [
|
|
930
|
+
flow,
|
|
931
|
+
beam,
|
|
932
|
+
bloom
|
|
933
|
+
];
|
|
676
934
|
function getShader(id) {
|
|
677
935
|
return shaders.find((s) => s.id === id);
|
|
678
936
|
}
|
|
@@ -1322,4 +1580,4 @@ function renderGradientFrame(opts) {
|
|
|
1322
1580
|
}
|
|
1323
1581
|
|
|
1324
1582
|
//#endregion
|
|
1325
|
-
export { beam, buildPaletteRamp, createRenderer, flow, getShader, mountGradient, renderGradientFrame, shaders };
|
|
1583
|
+
export { beam, bloom, buildPaletteRamp, createRenderer, flow, getShader, mountGradient, renderGradientFrame, shaders };
|