@wolsok/thanos 17.0.37 → 18.0.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 +73 -12
- package/esm2022/lib/canvas-particle-renderer.js +98 -0
- package/esm2022/lib/canvas-particle-renderer.js.map +1 -0
- package/esm2022/lib/capture-scale.js +13 -0
- package/esm2022/lib/capture-scale.js.map +1 -0
- package/esm2022/lib/choose-particle-renderer.js +78 -0
- package/esm2022/lib/choose-particle-renderer.js.map +1 -0
- package/esm2022/lib/create-ws-thanos-options.js +4 -1
- package/esm2022/lib/create-ws-thanos-options.js.map +1 -1
- package/esm2022/lib/crumble-shape.js +24 -0
- package/esm2022/lib/crumble-shape.js.map +1 -0
- package/esm2022/lib/particle-renderer.js +1 -0
- package/esm2022/lib/particle-renderer.js.map +1 -0
- package/esm2022/lib/particles.js +84 -0
- package/esm2022/lib/particles.js.map +1 -0
- package/esm2022/lib/snap-sound-envelopes.js +38 -0
- package/esm2022/lib/snap-sound-envelopes.js.map +1 -0
- package/esm2022/lib/snap-sound.service.js +287 -0
- package/esm2022/lib/snap-sound.service.js.map +1 -0
- package/esm2022/lib/vaporizing-front.js +48 -0
- package/esm2022/lib/vaporizing-front.js.map +1 -0
- package/esm2022/lib/webgl/simplex-noise.glsl.js +69 -0
- package/esm2022/lib/webgl/simplex-noise.glsl.js.map +1 -0
- package/esm2022/lib/webgl/webgl-particle-renderer.js +308 -0
- package/esm2022/lib/webgl/webgl-particle-renderer.js.map +1 -0
- package/esm2022/lib/webgl/webgl-shaders.js +323 -0
- package/esm2022/lib/webgl/webgl-shaders.js.map +1 -0
- package/esm2022/lib/ws-thanos.directive.js +8 -6
- package/esm2022/lib/ws-thanos.directive.js.map +1 -1
- package/esm2022/lib/ws-thanos.options.js.map +1 -1
- package/esm2022/lib/ws-thanos.service.js +103 -220
- package/esm2022/lib/ws-thanos.service.js.map +1 -1
- package/lib/canvas-particle-renderer.d.ts +29 -0
- package/lib/capture-scale.d.ts +14 -0
- package/lib/choose-particle-renderer.d.ts +31 -0
- package/lib/crumble-shape.d.ts +11 -0
- package/lib/particle-renderer.d.ts +26 -0
- package/lib/particles.d.ts +35 -0
- package/lib/snap-sound-envelopes.d.ts +15 -0
- package/lib/snap-sound.service.d.ts +27 -0
- package/lib/vaporizing-front.d.ts +34 -0
- package/lib/webgl/simplex-noise.glsl.d.ts +5 -0
- package/lib/webgl/webgl-particle-renderer.d.ts +46 -0
- package/lib/webgl/webgl-shaders.d.ts +27 -0
- package/lib/ws-thanos.directive.d.ts +4 -2
- package/lib/ws-thanos.options.d.ts +14 -0
- package/lib/ws-thanos.service.d.ts +11 -8
- package/package.json +1 -1
|
@@ -0,0 +1,287 @@
|
|
|
1
|
+
import { DOCUMENT, inject, Injectable } from '@angular/core';
|
|
2
|
+
import { RUMBLE_END, rumbleEnvelope, sandEnvelope, SILENT_AT, windEnvelope, } from './snap-sound-envelopes';
|
|
3
|
+
import * as i0 from "@angular/core";
|
|
4
|
+
const SILENT = { stop: () => undefined };
|
|
5
|
+
const NOISE_SEC = 2;
|
|
6
|
+
const FADE_OUT_SEC = 0.08;
|
|
7
|
+
const PEAK_GRAINS_PER_SEC = 70;
|
|
8
|
+
const PEAK_CRACKS_PER_SEC = 160;
|
|
9
|
+
/** many small cracks right when the element breaks: they crunch instead of banging like a shot */
|
|
10
|
+
const CRUNCH_CRACKS = 32;
|
|
11
|
+
const CRUNCH_SEC = 0.4;
|
|
12
|
+
/** points of the volume curves */
|
|
13
|
+
const CURVE_SAMPLES = 128;
|
|
14
|
+
/**
|
|
15
|
+
* Generates the snap sound with Web Audio, no audio files needed:
|
|
16
|
+
* the element breaks with a crunch, a rumble and cracks (dust only crackles thinly),
|
|
17
|
+
* then a gusty wind slowly grows stronger and carries hissing, crackling sand,
|
|
18
|
+
* all fading away in the last third.
|
|
19
|
+
* Every snap sounds a bit different.
|
|
20
|
+
*/
|
|
21
|
+
export class SnapSoundService {
|
|
22
|
+
constructor() {
|
|
23
|
+
this.window = inject(DOCUMENT).defaultView;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Play the snap sound. Stays silent when the browser does not allow audio yet,
|
|
27
|
+
* e.g. before the user interacted with the page.
|
|
28
|
+
*/
|
|
29
|
+
play(durationMs, volume, crumble) {
|
|
30
|
+
const audio = this.getAudio();
|
|
31
|
+
if (audio == null) {
|
|
32
|
+
return SILENT;
|
|
33
|
+
}
|
|
34
|
+
const { context, limiter, noise } = audio;
|
|
35
|
+
// every snap has its own volume, overlapping snaps don't change each other
|
|
36
|
+
const snapVolume = Math.min(1, Math.max(0, volume));
|
|
37
|
+
let voice;
|
|
38
|
+
let stopped = false;
|
|
39
|
+
const start = () => {
|
|
40
|
+
if (!stopped && context.state === 'running') {
|
|
41
|
+
voice = new SnapVoice(context, limiter, noise, durationMs / 1000, crumble, snapVolume);
|
|
42
|
+
}
|
|
43
|
+
};
|
|
44
|
+
if (context.state === 'running') {
|
|
45
|
+
start();
|
|
46
|
+
}
|
|
47
|
+
else {
|
|
48
|
+
context.resume().then(start, () => undefined);
|
|
49
|
+
}
|
|
50
|
+
return {
|
|
51
|
+
stop: () => {
|
|
52
|
+
stopped = true;
|
|
53
|
+
voice?.stop();
|
|
54
|
+
},
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
/** one audio context with a limiter and noise, shared by all snaps */
|
|
58
|
+
getAudio() {
|
|
59
|
+
if (this.audio) {
|
|
60
|
+
return this.audio;
|
|
61
|
+
}
|
|
62
|
+
const AudioContextCtor = this.window?.AudioContext;
|
|
63
|
+
const navigator = this.window?.navigator;
|
|
64
|
+
// creating a context before any user interaction only produces browser warnings
|
|
65
|
+
if (AudioContextCtor == null ||
|
|
66
|
+
navigator?.userActivation?.hasBeenActive === false) {
|
|
67
|
+
return undefined;
|
|
68
|
+
}
|
|
69
|
+
const context = new AudioContextCtor();
|
|
70
|
+
// a limiter keeps many simultaneous snaps from getting too loud
|
|
71
|
+
const limiter = context.createDynamicsCompressor();
|
|
72
|
+
limiter.threshold.setValueAtTime(-12, 0);
|
|
73
|
+
limiter.knee.setValueAtTime(6, 0);
|
|
74
|
+
limiter.ratio.setValueAtTime(12, 0);
|
|
75
|
+
limiter.attack.setValueAtTime(0.005, 0);
|
|
76
|
+
limiter.release.setValueAtTime(0.3, 0);
|
|
77
|
+
limiter.connect(context.destination);
|
|
78
|
+
this.audio = { context, limiter, noise: createNoiseBuffer(context) };
|
|
79
|
+
return this.audio;
|
|
80
|
+
}
|
|
81
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.2.1", ngImport: i0, type: SnapSoundService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
82
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.2.1", ngImport: i0, type: SnapSoundService, providedIn: 'root' }); }
|
|
83
|
+
}
|
|
84
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.2.1", ngImport: i0, type: SnapSoundService, decorators: [{
|
|
85
|
+
type: Injectable,
|
|
86
|
+
args: [{ providedIn: 'root' }]
|
|
87
|
+
}] });
|
|
88
|
+
/** pinkish noise: white noise with a gentle low pass, sounds softer and more natural */
|
|
89
|
+
function createNoiseBuffer(context) {
|
|
90
|
+
const length = Math.floor(context.sampleRate * NOISE_SEC);
|
|
91
|
+
const buffer = context.createBuffer(1, length, context.sampleRate);
|
|
92
|
+
const data = buffer.getChannelData(0);
|
|
93
|
+
let last = 0;
|
|
94
|
+
for (let i = 0; i < length; i++) {
|
|
95
|
+
last = last * 0.6 + (Math.random() * 2 - 1) * 0.4;
|
|
96
|
+
data[i] = last * 1.8;
|
|
97
|
+
}
|
|
98
|
+
return buffer;
|
|
99
|
+
}
|
|
100
|
+
const random = (min, max) => min + Math.random() * (max - min);
|
|
101
|
+
/** the sound layers of one snap: crunch, rumble, cracks, wind, hiss and sand */
|
|
102
|
+
class SnapVoice {
|
|
103
|
+
constructor(context, destination, noise, durationSec, crumble, volume) {
|
|
104
|
+
this.context = context;
|
|
105
|
+
this.noise = noise;
|
|
106
|
+
this.durationSec = durationSec;
|
|
107
|
+
this.sources = [];
|
|
108
|
+
this.start = context.currentTime;
|
|
109
|
+
this.output = context.createGain();
|
|
110
|
+
this.output.gain.setValueAtTime(volume, this.start);
|
|
111
|
+
this.output.connect(destination);
|
|
112
|
+
if (crumble === 'dust') {
|
|
113
|
+
// dust trickles away, it only crackles thinly
|
|
114
|
+
this.createCrackles(rumbleEnvelope, PEAK_CRACKS_PER_SEC / 2, [1800, 6000], 0.25);
|
|
115
|
+
}
|
|
116
|
+
else {
|
|
117
|
+
this.createCrunch();
|
|
118
|
+
this.createRumble();
|
|
119
|
+
this.createCrackles(rumbleEnvelope, PEAK_CRACKS_PER_SEC, [400, 2500], 0.6);
|
|
120
|
+
}
|
|
121
|
+
this.createWind();
|
|
122
|
+
this.createHiss();
|
|
123
|
+
this.createCrackles(sandEnvelope, PEAK_GRAINS_PER_SEC, [2500, 9000], 0.3);
|
|
124
|
+
}
|
|
125
|
+
stop() {
|
|
126
|
+
const now = this.context.currentTime;
|
|
127
|
+
this.output.gain.cancelScheduledValues(now);
|
|
128
|
+
this.output.gain.setTargetAtTime(0, now, FADE_OUT_SEC / 3);
|
|
129
|
+
this.sources.forEach((source) => source.stop(now + FADE_OUT_SEC));
|
|
130
|
+
}
|
|
131
|
+
/** audio context time at the given animation progress */
|
|
132
|
+
at(progress) {
|
|
133
|
+
return this.start + this.durationSec * progress;
|
|
134
|
+
}
|
|
135
|
+
/** the element breaks: a quick, dense cluster of cracks that gets quieter */
|
|
136
|
+
createCrunch() {
|
|
137
|
+
for (let i = 0; i < CRUNCH_CRACKS; i++) {
|
|
138
|
+
// most cracks right at the start
|
|
139
|
+
const delay = CRUNCH_SEC * Math.pow(Math.random(), 1.6);
|
|
140
|
+
const fading = 1 - delay / (CRUNCH_SEC * 1.25);
|
|
141
|
+
this.createBurst(this.start + delay, {
|
|
142
|
+
peak: 0.75 * fading * random(0.5, 1),
|
|
143
|
+
attack: random(0.004, 0.01),
|
|
144
|
+
decay: random(0.02, 0.07),
|
|
145
|
+
frequency: random(300, 2200),
|
|
146
|
+
q: random(1, 3),
|
|
147
|
+
});
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
/** the element breaks: low rumbling noise and a dull thump */
|
|
151
|
+
createRumble() {
|
|
152
|
+
const { context, start } = this;
|
|
153
|
+
const source = this.noiseSource();
|
|
154
|
+
const filter = context.createBiquadFilter();
|
|
155
|
+
filter.type = 'lowpass';
|
|
156
|
+
filter.frequency.setValueAtTime(random(140, 200), start);
|
|
157
|
+
filter.Q.setValueAtTime(1.2, start);
|
|
158
|
+
const gain = this.envelopeGain(rumbleEnvelope, 1, RUMBLE_END);
|
|
159
|
+
source.connect(filter).connect(gain).connect(this.output);
|
|
160
|
+
this.startSource(source, start, this.at(RUMBLE_END));
|
|
161
|
+
const thump = context.createOscillator();
|
|
162
|
+
thump.frequency.setValueAtTime(random(55, 70), start);
|
|
163
|
+
thump.frequency.exponentialRampToValueAtTime(32, start + 0.4);
|
|
164
|
+
const thumpGain = context.createGain();
|
|
165
|
+
// a soft rise makes it a thump, not a bang
|
|
166
|
+
thumpGain.gain.setValueAtTime(0.0001, start);
|
|
167
|
+
thumpGain.gain.linearRampToValueAtTime(0.6, start + 0.03);
|
|
168
|
+
thumpGain.gain.exponentialRampToValueAtTime(0.0001, start + 0.5);
|
|
169
|
+
thump.connect(thumpGain).connect(this.output);
|
|
170
|
+
this.startSource(thump, start, start + 0.55);
|
|
171
|
+
}
|
|
172
|
+
/** wind that slowly grows stronger in gusts, it gets brighter the stronger it blows */
|
|
173
|
+
createWind() {
|
|
174
|
+
const { context, start } = this;
|
|
175
|
+
const source = this.noiseSource();
|
|
176
|
+
source.playbackRate.setValueAtTime(random(0.85, 1.15), start);
|
|
177
|
+
const brightness = random(500, 700);
|
|
178
|
+
const filter = context.createBiquadFilter();
|
|
179
|
+
filter.type = 'bandpass';
|
|
180
|
+
filter.Q.setValueAtTime(0.9, start);
|
|
181
|
+
filter.frequency.setValueCurveAtTime(sampleCurve((progress) => 250 + brightness * windEnvelope(progress), SILENT_AT), start, this.durationSec * SILENT_AT);
|
|
182
|
+
// gusts: a slow oscillator wobbles the wind volume around 1
|
|
183
|
+
const gusts = context.createGain();
|
|
184
|
+
gusts.gain.setValueAtTime(1, start);
|
|
185
|
+
const gust = context.createOscillator();
|
|
186
|
+
gust.frequency.setValueAtTime(random(0.3, 0.7), start);
|
|
187
|
+
const gustDepth = context.createGain();
|
|
188
|
+
gustDepth.gain.setValueAtTime(0.3, start);
|
|
189
|
+
gust.connect(gustDepth).connect(gusts.gain);
|
|
190
|
+
const gain = this.envelopeGain(windEnvelope, 0.4);
|
|
191
|
+
source.connect(filter).connect(gusts).connect(gain).connect(this.output);
|
|
192
|
+
this.startSource(source, start, this.at(SILENT_AT));
|
|
193
|
+
this.startSource(gust, start, this.at(SILENT_AT));
|
|
194
|
+
}
|
|
195
|
+
/** bright hiss of the sand blown by the wind */
|
|
196
|
+
createHiss() {
|
|
197
|
+
const { context, start } = this;
|
|
198
|
+
const source = this.noiseSource();
|
|
199
|
+
const filter = context.createBiquadFilter();
|
|
200
|
+
filter.type = 'highpass';
|
|
201
|
+
filter.frequency.setValueAtTime(random(3500, 4500), start);
|
|
202
|
+
filter.Q.setValueAtTime(0.7, start);
|
|
203
|
+
const gain = this.envelopeGain(sandEnvelope, 0.2);
|
|
204
|
+
source.connect(filter).connect(gain).connect(this.output);
|
|
205
|
+
this.startSource(source, start, this.at(SILENT_AT));
|
|
206
|
+
}
|
|
207
|
+
/**
|
|
208
|
+
* Short noise bursts: cracks while the element breaks, sand grains in the wind.
|
|
209
|
+
* The envelope sets how dense and loud they are.
|
|
210
|
+
*/
|
|
211
|
+
createCrackles(envelope, peakPerSec, [minFrequency, maxFrequency], loudness) {
|
|
212
|
+
const { durationSec } = this;
|
|
213
|
+
const end = durationSec * SILENT_AT;
|
|
214
|
+
let t = 0;
|
|
215
|
+
for (;;) {
|
|
216
|
+
t += -Math.log(1 - Math.random()) / peakPerSec;
|
|
217
|
+
const attack = random(0.002, 0.006);
|
|
218
|
+
const decay = random(0.004, 0.025);
|
|
219
|
+
if (t + attack + decay > end) {
|
|
220
|
+
break;
|
|
221
|
+
}
|
|
222
|
+
const density = envelope(t / durationSec);
|
|
223
|
+
if (Math.random() > density) {
|
|
224
|
+
continue;
|
|
225
|
+
}
|
|
226
|
+
this.createBurst(this.start + t, {
|
|
227
|
+
peak: loudness * random(0.3, 1) * density,
|
|
228
|
+
attack,
|
|
229
|
+
decay,
|
|
230
|
+
frequency: random(minFrequency, maxFrequency),
|
|
231
|
+
q: random(2, 6),
|
|
232
|
+
});
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
/** one short noise burst, the soft attack keeps it from sounding like a shot */
|
|
236
|
+
createBurst(when, { peak, attack, decay, frequency, q }) {
|
|
237
|
+
const { context } = this;
|
|
238
|
+
const source = this.noiseSource(false);
|
|
239
|
+
const filter = context.createBiquadFilter();
|
|
240
|
+
filter.type = 'bandpass';
|
|
241
|
+
filter.frequency.setValueAtTime(frequency, when);
|
|
242
|
+
filter.Q.setValueAtTime(q, when);
|
|
243
|
+
const gain = context.createGain();
|
|
244
|
+
gain.gain.setValueAtTime(0.0001, when);
|
|
245
|
+
gain.gain.linearRampToValueAtTime(peak, when + attack);
|
|
246
|
+
gain.gain.exponentialRampToValueAtTime(0.0001, when + attack + decay);
|
|
247
|
+
source.connect(filter).connect(gain).connect(this.output);
|
|
248
|
+
this.startSource(source, when, when + attack + decay);
|
|
249
|
+
}
|
|
250
|
+
/** a gain that follows the envelope from the start until the given animation progress */
|
|
251
|
+
envelopeGain(envelope, loudness, until = SILENT_AT) {
|
|
252
|
+
const gain = this.context.createGain();
|
|
253
|
+
gain.gain.setValueCurveAtTime(sampleCurve((progress) => loudness * envelope(progress), until), this.start, this.durationSec * until);
|
|
254
|
+
return gain;
|
|
255
|
+
}
|
|
256
|
+
noiseSource(loop = true) {
|
|
257
|
+
const source = this.context.createBufferSource();
|
|
258
|
+
source.buffer = this.noise;
|
|
259
|
+
source.loop = loop;
|
|
260
|
+
return source;
|
|
261
|
+
}
|
|
262
|
+
/** start a source now or later and stop it at the given time */
|
|
263
|
+
startSource(source, when, until) {
|
|
264
|
+
if (source.buffer != null) {
|
|
265
|
+
// every noise starts at a random position of the noise buffer
|
|
266
|
+
source.start(when, random(0, NOISE_SEC - 0.05));
|
|
267
|
+
}
|
|
268
|
+
else {
|
|
269
|
+
source.start(when);
|
|
270
|
+
}
|
|
271
|
+
this.scheduleStop(source, until);
|
|
272
|
+
}
|
|
273
|
+
scheduleStop(source, until) {
|
|
274
|
+
source.stop(until);
|
|
275
|
+
source.onended = () => source.disconnect();
|
|
276
|
+
this.sources.push(source);
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
/** sample an envelope from the start of the animation until the given progress */
|
|
280
|
+
function sampleCurve(envelope, until) {
|
|
281
|
+
const curve = new Float32Array(CURVE_SAMPLES);
|
|
282
|
+
for (let i = 0; i < CURVE_SAMPLES; i++) {
|
|
283
|
+
curve[i] = envelope((i / (CURVE_SAMPLES - 1)) * until);
|
|
284
|
+
}
|
|
285
|
+
return curve;
|
|
286
|
+
}
|
|
287
|
+
//# sourceMappingURL=snap-sound.service.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"snap-sound.service.js","sourceRoot":"","sources":["../../../../../../libs/public/ws-thanos/src/lib/snap-sound.service.ts"],"names":[],"mappings":"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","sourcesContent":["import { DOCUMENT, inject, Injectable } from '@angular/core';\nimport type { WsThanosCrumble } from './ws-thanos.options';\nimport {\n RUMBLE_END,\n rumbleEnvelope,\n sandEnvelope,\n SILENT_AT,\n windEnvelope,\n} from './snap-sound-envelopes';\n\n/** a playing snap sound */\nexport interface SnapSound {\n /** fade out quickly and free the sound */\n stop(): void;\n}\n\nconst SILENT: SnapSound = { stop: () => undefined };\n\nconst NOISE_SEC = 2;\nconst FADE_OUT_SEC = 0.08;\nconst PEAK_GRAINS_PER_SEC = 70;\nconst PEAK_CRACKS_PER_SEC = 160;\n/** many small cracks right when the element breaks: they crunch instead of banging like a shot */\nconst CRUNCH_CRACKS = 32;\nconst CRUNCH_SEC = 0.4;\n/** points of the volume curves */\nconst CURVE_SAMPLES = 128;\n\ninterface SharedAudio {\n context: AudioContext;\n /** limits all snaps together */\n limiter: AudioNode;\n noise: AudioBuffer;\n}\n\ninterface UserActivationNavigator {\n userActivation?: { hasBeenActive: boolean };\n}\n\n/**\n * Generates the snap sound with Web Audio, no audio files needed:\n * the element breaks with a crunch, a rumble and cracks (dust only crackles thinly),\n * then a gusty wind slowly grows stronger and carries hissing, crackling sand,\n * all fading away in the last third.\n * Every snap sounds a bit different.\n */\n@Injectable({ providedIn: 'root' })\nexport class SnapSoundService {\n private readonly window = inject(DOCUMENT).defaultView as\n | (Window & { AudioContext?: typeof AudioContext })\n | null;\n private audio?: SharedAudio;\n\n /**\n * Play the snap sound. Stays silent when the browser does not allow audio yet,\n * e.g. before the user interacted with the page.\n */\n public play(\n durationMs: number,\n volume: number,\n crumble: WsThanosCrumble\n ): SnapSound {\n const audio = this.getAudio();\n if (audio == null) {\n return SILENT;\n }\n const { context, limiter, noise } = audio;\n // every snap has its own volume, overlapping snaps don't change each other\n const snapVolume = Math.min(1, Math.max(0, volume));\n\n let voice: SnapVoice | undefined;\n let stopped = false;\n const start = () => {\n if (!stopped && context.state === 'running') {\n voice = new SnapVoice(\n context,\n limiter,\n noise,\n durationMs / 1000,\n crumble,\n snapVolume\n );\n }\n };\n\n if (context.state === 'running') {\n start();\n } else {\n context.resume().then(start, () => undefined);\n }\n\n return {\n stop: () => {\n stopped = true;\n voice?.stop();\n },\n };\n }\n\n /** one audio context with a limiter and noise, shared by all snaps */\n private getAudio(): SharedAudio | undefined {\n if (this.audio) {\n return this.audio;\n }\n const AudioContextCtor = this.window?.AudioContext;\n const navigator = this.window?.navigator as UserActivationNavigator;\n // creating a context before any user interaction only produces browser warnings\n if (\n AudioContextCtor == null ||\n navigator?.userActivation?.hasBeenActive === false\n ) {\n return undefined;\n }\n\n const context = new AudioContextCtor();\n // a limiter keeps many simultaneous snaps from getting too loud\n const limiter = context.createDynamicsCompressor();\n limiter.threshold.setValueAtTime(-12, 0);\n limiter.knee.setValueAtTime(6, 0);\n limiter.ratio.setValueAtTime(12, 0);\n limiter.attack.setValueAtTime(0.005, 0);\n limiter.release.setValueAtTime(0.3, 0);\n limiter.connect(context.destination);\n\n this.audio = { context, limiter, noise: createNoiseBuffer(context) };\n return this.audio;\n }\n}\n\n/** pinkish noise: white noise with a gentle low pass, sounds softer and more natural */\nfunction createNoiseBuffer(context: AudioContext): AudioBuffer {\n const length = Math.floor(context.sampleRate * NOISE_SEC);\n const buffer = context.createBuffer(1, length, context.sampleRate);\n const data = buffer.getChannelData(0);\n let last = 0;\n for (let i = 0; i < length; i++) {\n last = last * 0.6 + (Math.random() * 2 - 1) * 0.4;\n data[i] = last * 1.8;\n }\n return buffer;\n}\n\nconst random = (min: number, max: number) => min + Math.random() * (max - min);\n\ninterface Burst {\n peak: number;\n attack: number;\n decay: number;\n frequency: number;\n q: number;\n}\n\n/** the sound layers of one snap: crunch, rumble, cracks, wind, hiss and sand */\nclass SnapVoice {\n private readonly output: GainNode;\n private readonly sources: AudioScheduledSourceNode[] = [];\n private readonly start: number;\n\n public constructor(\n private readonly context: AudioContext,\n destination: AudioNode,\n private readonly noise: AudioBuffer,\n private readonly durationSec: number,\n crumble: WsThanosCrumble,\n volume: number\n ) {\n this.start = context.currentTime;\n this.output = context.createGain();\n this.output.gain.setValueAtTime(volume, this.start);\n this.output.connect(destination);\n\n if (crumble === 'dust') {\n // dust trickles away, it only crackles thinly\n this.createCrackles(\n rumbleEnvelope,\n PEAK_CRACKS_PER_SEC / 2,\n [1800, 6000],\n 0.25\n );\n } else {\n this.createCrunch();\n this.createRumble();\n this.createCrackles(\n rumbleEnvelope,\n PEAK_CRACKS_PER_SEC,\n [400, 2500],\n 0.6\n );\n }\n this.createWind();\n this.createHiss();\n this.createCrackles(sandEnvelope, PEAK_GRAINS_PER_SEC, [2500, 9000], 0.3);\n }\n\n public stop(): void {\n const now = this.context.currentTime;\n this.output.gain.cancelScheduledValues(now);\n this.output.gain.setTargetAtTime(0, now, FADE_OUT_SEC / 3);\n this.sources.forEach((source) => source.stop(now + FADE_OUT_SEC));\n }\n\n /** audio context time at the given animation progress */\n private at(progress: number): number {\n return this.start + this.durationSec * progress;\n }\n\n /** the element breaks: a quick, dense cluster of cracks that gets quieter */\n private createCrunch(): void {\n for (let i = 0; i < CRUNCH_CRACKS; i++) {\n // most cracks right at the start\n const delay = CRUNCH_SEC * Math.pow(Math.random(), 1.6);\n const fading = 1 - delay / (CRUNCH_SEC * 1.25);\n this.createBurst(this.start + delay, {\n peak: 0.75 * fading * random(0.5, 1),\n attack: random(0.004, 0.01),\n decay: random(0.02, 0.07),\n frequency: random(300, 2200),\n q: random(1, 3),\n });\n }\n }\n\n /** the element breaks: low rumbling noise and a dull thump */\n private createRumble(): void {\n const { context, start } = this;\n\n const source = this.noiseSource();\n const filter = context.createBiquadFilter();\n filter.type = 'lowpass';\n filter.frequency.setValueAtTime(random(140, 200), start);\n filter.Q.setValueAtTime(1.2, start);\n const gain = this.envelopeGain(rumbleEnvelope, 1, RUMBLE_END);\n source.connect(filter).connect(gain).connect(this.output);\n this.startSource(source, start, this.at(RUMBLE_END));\n\n const thump = context.createOscillator();\n thump.frequency.setValueAtTime(random(55, 70), start);\n thump.frequency.exponentialRampToValueAtTime(32, start + 0.4);\n const thumpGain = context.createGain();\n // a soft rise makes it a thump, not a bang\n thumpGain.gain.setValueAtTime(0.0001, start);\n thumpGain.gain.linearRampToValueAtTime(0.6, start + 0.03);\n thumpGain.gain.exponentialRampToValueAtTime(0.0001, start + 0.5);\n thump.connect(thumpGain).connect(this.output);\n this.startSource(thump, start, start + 0.55);\n }\n\n /** wind that slowly grows stronger in gusts, it gets brighter the stronger it blows */\n private createWind(): void {\n const { context, start } = this;\n const source = this.noiseSource();\n source.playbackRate.setValueAtTime(random(0.85, 1.15), start);\n\n const brightness = random(500, 700);\n const filter = context.createBiquadFilter();\n filter.type = 'bandpass';\n filter.Q.setValueAtTime(0.9, start);\n filter.frequency.setValueCurveAtTime(\n sampleCurve(\n (progress) => 250 + brightness * windEnvelope(progress),\n SILENT_AT\n ),\n start,\n this.durationSec * SILENT_AT\n );\n\n // gusts: a slow oscillator wobbles the wind volume around 1\n const gusts = context.createGain();\n gusts.gain.setValueAtTime(1, start);\n const gust = context.createOscillator();\n gust.frequency.setValueAtTime(random(0.3, 0.7), start);\n const gustDepth = context.createGain();\n gustDepth.gain.setValueAtTime(0.3, start);\n gust.connect(gustDepth).connect(gusts.gain);\n\n const gain = this.envelopeGain(windEnvelope, 0.4);\n source.connect(filter).connect(gusts).connect(gain).connect(this.output);\n this.startSource(source, start, this.at(SILENT_AT));\n this.startSource(gust, start, this.at(SILENT_AT));\n }\n\n /** bright hiss of the sand blown by the wind */\n private createHiss(): void {\n const { context, start } = this;\n const source = this.noiseSource();\n const filter = context.createBiquadFilter();\n filter.type = 'highpass';\n filter.frequency.setValueAtTime(random(3500, 4500), start);\n filter.Q.setValueAtTime(0.7, start);\n const gain = this.envelopeGain(sandEnvelope, 0.2);\n source.connect(filter).connect(gain).connect(this.output);\n this.startSource(source, start, this.at(SILENT_AT));\n }\n\n /**\n * Short noise bursts: cracks while the element breaks, sand grains in the wind.\n * The envelope sets how dense and loud they are.\n */\n private createCrackles(\n envelope: (progress: number) => number,\n peakPerSec: number,\n [minFrequency, maxFrequency]: [number, number],\n loudness: number\n ): void {\n const { durationSec } = this;\n const end = durationSec * SILENT_AT;\n let t = 0;\n for (;;) {\n t += -Math.log(1 - Math.random()) / peakPerSec;\n const attack = random(0.002, 0.006);\n const decay = random(0.004, 0.025);\n if (t + attack + decay > end) {\n break;\n }\n const density = envelope(t / durationSec);\n if (Math.random() > density) {\n continue;\n }\n this.createBurst(this.start + t, {\n peak: loudness * random(0.3, 1) * density,\n attack,\n decay,\n frequency: random(minFrequency, maxFrequency),\n q: random(2, 6),\n });\n }\n }\n\n /** one short noise burst, the soft attack keeps it from sounding like a shot */\n private createBurst(\n when: number,\n { peak, attack, decay, frequency, q }: Burst\n ): void {\n const { context } = this;\n const source = this.noiseSource(false);\n\n const filter = context.createBiquadFilter();\n filter.type = 'bandpass';\n filter.frequency.setValueAtTime(frequency, when);\n filter.Q.setValueAtTime(q, when);\n\n const gain = context.createGain();\n gain.gain.setValueAtTime(0.0001, when);\n gain.gain.linearRampToValueAtTime(peak, when + attack);\n gain.gain.exponentialRampToValueAtTime(0.0001, when + attack + decay);\n\n source.connect(filter).connect(gain).connect(this.output);\n this.startSource(source, when, when + attack + decay);\n }\n\n /** a gain that follows the envelope from the start until the given animation progress */\n private envelopeGain(\n envelope: (progress: number) => number,\n loudness: number,\n until = SILENT_AT\n ): GainNode {\n const gain = this.context.createGain();\n gain.gain.setValueCurveAtTime(\n sampleCurve((progress) => loudness * envelope(progress), until),\n this.start,\n this.durationSec * until\n );\n return gain;\n }\n\n private noiseSource(loop = true): AudioBufferSourceNode {\n const source = this.context.createBufferSource();\n source.buffer = this.noise;\n source.loop = loop;\n return source;\n }\n\n /** start a source now or later and stop it at the given time */\n private startSource(\n source: AudioScheduledSourceNode,\n when: number,\n until: number\n ): void {\n if ((source as AudioBufferSourceNode).buffer != null) {\n // every noise starts at a random position of the noise buffer\n (source as AudioBufferSourceNode).start(\n when,\n random(0, NOISE_SEC - 0.05)\n );\n } else {\n source.start(when);\n }\n this.scheduleStop(source, until);\n }\n\n private scheduleStop(source: AudioScheduledSourceNode, until: number): void {\n source.stop(until);\n source.onended = () => source.disconnect();\n this.sources.push(source);\n }\n}\n\n/** sample an envelope from the start of the animation until the given progress */\nfunction sampleCurve(\n envelope: (progress: number) => number,\n until: number\n): Float32Array {\n const curve = new Float32Array(CURVE_SAMPLES);\n for (let i = 0; i < CURVE_SAMPLES; i++) {\n curve[i] = envelope((i / (CURVE_SAMPLES - 1)) * until);\n }\n return curve;\n}\n"]}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The vaporizing front sweeps from the top right to the bottom left of the element.
|
|
3
|
+
* Shared by the CPU and the GPU simulation, the GPU gets the values below as uniforms
|
|
4
|
+
* and the constants interpolated into its shader.
|
|
5
|
+
*/
|
|
6
|
+
/** some random looking waves give the front a frayed edge */
|
|
7
|
+
export const FRONT_FRAY = {
|
|
8
|
+
xWave: 30,
|
|
9
|
+
xPhase: 723.394,
|
|
10
|
+
xSeed: 12.5,
|
|
11
|
+
xAmplitude: 11,
|
|
12
|
+
yWave: 100,
|
|
13
|
+
yPhase: 2323.234,
|
|
14
|
+
ySeed: 456.1,
|
|
15
|
+
yAmplitude: 23,
|
|
16
|
+
};
|
|
17
|
+
/** the noise field released particles flow along */
|
|
18
|
+
export const FLOW_FIELD = {
|
|
19
|
+
frequency: 0.01,
|
|
20
|
+
xSeedOffset: 33.23,
|
|
21
|
+
ySeedDivisor: 13.23,
|
|
22
|
+
};
|
|
23
|
+
/** where the front is at the given animation progress */
|
|
24
|
+
export function vaporizingFront(animationT, maxParticleX, minParticleY, height) {
|
|
25
|
+
const time = Math.sin(animationT * (Math.PI / 2)) * 1.1;
|
|
26
|
+
const startAccelerateX = maxParticleX - time * maxParticleX;
|
|
27
|
+
const startAccelerateY = time * (height - minParticleY) + minParticleY;
|
|
28
|
+
const lengthY = height - startAccelerateY;
|
|
29
|
+
return {
|
|
30
|
+
time,
|
|
31
|
+
radiusPow: startAccelerateX * startAccelerateX + lengthY * lengthY,
|
|
32
|
+
fade: 1 - Math.pow(animationT, 15),
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
/** has the front passed the particle at x, y. No tan() waves: their poles break off whole rows */
|
|
36
|
+
export function isBehindFront(x, y, height, deltaTSec, seed, { time, radiusPow }) {
|
|
37
|
+
const f = FRONT_FRAY;
|
|
38
|
+
let pXLength = x + (x % deltaTSec) * 0.5;
|
|
39
|
+
let pYLength = height - y;
|
|
40
|
+
pXLength +=
|
|
41
|
+
Math.sin((pXLength / f.xWave + f.xPhase) * time + seed * f.xSeed) *
|
|
42
|
+
f.xAmplitude;
|
|
43
|
+
pYLength +=
|
|
44
|
+
Math.cos((pYLength / f.yWave + f.yPhase) * time + seed * f.ySeed) *
|
|
45
|
+
f.yAmplitude;
|
|
46
|
+
return pXLength * pXLength + pYLength * pYLength > radiusPow;
|
|
47
|
+
}
|
|
48
|
+
//# sourceMappingURL=vaporizing-front.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"vaporizing-front.js","sourceRoot":"","sources":["../../../../../../libs/public/ws-thanos/src/lib/vaporizing-front.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,6DAA6D;AAC7D,MAAM,CAAC,MAAM,UAAU,GAAG;IACxB,KAAK,EAAE,EAAE;IACT,MAAM,EAAE,OAAO;IACf,KAAK,EAAE,IAAI;IACX,UAAU,EAAE,EAAE;IACd,KAAK,EAAE,GAAG;IACV,MAAM,EAAE,QAAQ;IAChB,KAAK,EAAE,KAAK;IACZ,UAAU,EAAE,EAAE;CACN,CAAC;AAEX,oDAAoD;AACpD,MAAM,CAAC,MAAM,UAAU,GAAG;IACxB,SAAS,EAAE,IAAI;IACf,WAAW,EAAE,KAAK;IAClB,YAAY,EAAE,KAAK;CACX,CAAC;AAWX,yDAAyD;AACzD,MAAM,UAAU,eAAe,CAC7B,UAAkB,EAClB,YAAoB,EACpB,YAAoB,EACpB,MAAc;IAEd,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG,CAAC,UAAU,GAAG,CAAC,IAAI,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC;IACxD,MAAM,gBAAgB,GAAG,YAAY,GAAG,IAAI,GAAG,YAAY,CAAC;IAC5D,MAAM,gBAAgB,GAAG,IAAI,GAAG,CAAC,MAAM,GAAG,YAAY,CAAC,GAAG,YAAY,CAAC;IACvE,MAAM,OAAO,GAAG,MAAM,GAAG,gBAAgB,CAAC;IAC1C,OAAO;QACL,IAAI;QACJ,SAAS,EAAE,gBAAgB,GAAG,gBAAgB,GAAG,OAAO,GAAG,OAAO;QAClE,IAAI,EAAE,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,UAAU,EAAE,EAAE,CAAC;KACnC,CAAC;AACJ,CAAC;AAED,kGAAkG;AAClG,MAAM,UAAU,aAAa,CAC3B,CAAS,EACT,CAAS,EACT,MAAc,EACd,SAAiB,EACjB,IAAY,EACZ,EAAE,IAAI,EAAE,SAAS,EAAmB;IAEpC,MAAM,CAAC,GAAG,UAAU,CAAC;IACrB,IAAI,QAAQ,GAAG,CAAC,GAAG,CAAC,CAAC,GAAG,SAAS,CAAC,GAAG,GAAG,CAAC;IACzC,IAAI,QAAQ,GAAG,MAAM,GAAG,CAAC,CAAC;IAC1B,QAAQ;QACN,IAAI,CAAC,GAAG,CAAC,CAAC,QAAQ,GAAG,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,MAAM,CAAC,GAAG,IAAI,GAAG,IAAI,GAAG,CAAC,CAAC,KAAK,CAAC;YACjE,CAAC,CAAC,UAAU,CAAC;IACf,QAAQ;QACN,IAAI,CAAC,GAAG,CAAC,CAAC,QAAQ,GAAG,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,MAAM,CAAC,GAAG,IAAI,GAAG,IAAI,GAAG,CAAC,CAAC,KAAK,CAAC;YACjE,CAAC,CAAC,UAAU,CAAC;IACf,OAAO,QAAQ,GAAG,QAAQ,GAAG,QAAQ,GAAG,QAAQ,GAAG,SAAS,CAAC;AAC/D,CAAC","sourcesContent":["/**\n * The vaporizing front sweeps from the top right to the bottom left of the element.\n * Shared by the CPU and the GPU simulation, the GPU gets the values below as uniforms\n * and the constants interpolated into its shader.\n */\n\n/** some random looking waves give the front a frayed edge */\nexport const FRONT_FRAY = {\n xWave: 30,\n xPhase: 723.394,\n xSeed: 12.5,\n xAmplitude: 11,\n yWave: 100,\n yPhase: 2323.234,\n ySeed: 456.1,\n yAmplitude: 23,\n} as const;\n\n/** the noise field released particles flow along */\nexport const FLOW_FIELD = {\n frequency: 0.01,\n xSeedOffset: 33.23,\n ySeedDivisor: 13.23,\n} as const;\n\nexport interface VaporizingFront {\n /** drives the fray waves */\n time: number;\n /** particles further than this (squared) from the bottom left corner break off */\n radiusPow: number;\n /** alpha factor that fades the particles out very late */\n fade: number;\n}\n\n/** where the front is at the given animation progress */\nexport function vaporizingFront(\n animationT: number,\n maxParticleX: number,\n minParticleY: number,\n height: number\n): VaporizingFront {\n const time = Math.sin(animationT * (Math.PI / 2)) * 1.1;\n const startAccelerateX = maxParticleX - time * maxParticleX;\n const startAccelerateY = time * (height - minParticleY) + minParticleY;\n const lengthY = height - startAccelerateY;\n return {\n time,\n radiusPow: startAccelerateX * startAccelerateX + lengthY * lengthY,\n fade: 1 - Math.pow(animationT, 15),\n };\n}\n\n/** has the front passed the particle at x, y. No tan() waves: their poles break off whole rows */\nexport function isBehindFront(\n x: number,\n y: number,\n height: number,\n deltaTSec: number,\n seed: number,\n { time, radiusPow }: VaporizingFront\n): boolean {\n const f = FRONT_FRAY;\n let pXLength = x + (x % deltaTSec) * 0.5;\n let pYLength = height - y;\n pXLength +=\n Math.sin((pXLength / f.xWave + f.xPhase) * time + seed * f.xSeed) *\n f.xAmplitude;\n pYLength +=\n Math.cos((pYLength / f.yWave + f.yPhase) * time + seed * f.ySeed) *\n f.yAmplitude;\n return pXLength * pXLength + pYLength * pYLength > radiusPow;\n}\n"]}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 3D simplex noise by Ian McEwan, Ashima Arts (MIT License)
|
|
3
|
+
* https://github.com/ashima/webgl-noise
|
|
4
|
+
*/
|
|
5
|
+
export const SIMPLEX_NOISE_3D = /* glsl */ `
|
|
6
|
+
vec3 mod289(vec3 x) { return x - floor(x * (1.0 / 289.0)) * 289.0; }
|
|
7
|
+
vec4 mod289(vec4 x) { return x - floor(x * (1.0 / 289.0)) * 289.0; }
|
|
8
|
+
vec4 permute(vec4 x) { return mod289(((x * 34.0) + 10.0) * x); }
|
|
9
|
+
vec4 taylorInvSqrt(vec4 r) { return 1.79284291400159 - 0.85373472095314 * r; }
|
|
10
|
+
|
|
11
|
+
float snoise(vec3 v) {
|
|
12
|
+
const vec2 C = vec2(1.0 / 6.0, 1.0 / 3.0);
|
|
13
|
+
const vec4 D = vec4(0.0, 0.5, 1.0, 2.0);
|
|
14
|
+
|
|
15
|
+
vec3 i = floor(v + dot(v, C.yyy));
|
|
16
|
+
vec3 x0 = v - i + dot(i, C.xxx);
|
|
17
|
+
|
|
18
|
+
vec3 g = step(x0.yzx, x0.xyz);
|
|
19
|
+
vec3 l = 1.0 - g;
|
|
20
|
+
vec3 i1 = min(g.xyz, l.zxy);
|
|
21
|
+
vec3 i2 = max(g.xyz, l.zxy);
|
|
22
|
+
|
|
23
|
+
vec3 x1 = x0 - i1 + C.xxx;
|
|
24
|
+
vec3 x2 = x0 - i2 + C.yyy;
|
|
25
|
+
vec3 x3 = x0 - D.yyy;
|
|
26
|
+
|
|
27
|
+
i = mod289(i);
|
|
28
|
+
vec4 p = permute(permute(permute(
|
|
29
|
+
i.z + vec4(0.0, i1.z, i2.z, 1.0))
|
|
30
|
+
+ i.y + vec4(0.0, i1.y, i2.y, 1.0))
|
|
31
|
+
+ i.x + vec4(0.0, i1.x, i2.x, 1.0));
|
|
32
|
+
|
|
33
|
+
float n_ = 0.142857142857;
|
|
34
|
+
vec3 ns = n_ * D.wyz - D.xzx;
|
|
35
|
+
|
|
36
|
+
vec4 j = p - 49.0 * floor(p * ns.z * ns.z);
|
|
37
|
+
vec4 x_ = floor(j * ns.z);
|
|
38
|
+
vec4 y_ = floor(j - 7.0 * x_);
|
|
39
|
+
|
|
40
|
+
vec4 x = x_ * ns.x + ns.yyyy;
|
|
41
|
+
vec4 y = y_ * ns.x + ns.yyyy;
|
|
42
|
+
vec4 h = 1.0 - abs(x) - abs(y);
|
|
43
|
+
|
|
44
|
+
vec4 b0 = vec4(x.xy, y.xy);
|
|
45
|
+
vec4 b1 = vec4(x.zw, y.zw);
|
|
46
|
+
vec4 s0 = floor(b0) * 2.0 + 1.0;
|
|
47
|
+
vec4 s1 = floor(b1) * 2.0 + 1.0;
|
|
48
|
+
vec4 sh = -step(h, vec4(0.0));
|
|
49
|
+
|
|
50
|
+
vec4 a0 = b0.xzyw + s0.xzyw * sh.xxyy;
|
|
51
|
+
vec4 a1 = b1.xzyw + s1.xzyw * sh.zzww;
|
|
52
|
+
|
|
53
|
+
vec3 p0 = vec3(a0.xy, h.x);
|
|
54
|
+
vec3 p1 = vec3(a0.zw, h.y);
|
|
55
|
+
vec3 p2 = vec3(a1.xy, h.z);
|
|
56
|
+
vec3 p3 = vec3(a1.zw, h.w);
|
|
57
|
+
|
|
58
|
+
vec4 norm = taylorInvSqrt(vec4(dot(p0, p0), dot(p1, p1), dot(p2, p2), dot(p3, p3)));
|
|
59
|
+
p0 *= norm.x;
|
|
60
|
+
p1 *= norm.y;
|
|
61
|
+
p2 *= norm.z;
|
|
62
|
+
p3 *= norm.w;
|
|
63
|
+
|
|
64
|
+
vec4 m = max(0.5 - vec4(dot(x0, x0), dot(x1, x1), dot(x2, x2), dot(x3, x3)), 0.0);
|
|
65
|
+
m = m * m;
|
|
66
|
+
return 105.0 * dot(m * m, vec4(dot(p0, x0), dot(p1, x1), dot(p2, x2), dot(p3, x3)));
|
|
67
|
+
}
|
|
68
|
+
`;
|
|
69
|
+
//# sourceMappingURL=simplex-noise.glsl.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"simplex-noise.glsl.js","sourceRoot":"","sources":["../../../../../../../libs/public/ws-thanos/src/lib/webgl/simplex-noise.glsl.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAAG,UAAU,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA+D1C,CAAC","sourcesContent":["/**\n * 3D simplex noise by Ian McEwan, Ashima Arts (MIT License)\n * https://github.com/ashima/webgl-noise\n */\nexport const SIMPLEX_NOISE_3D = /* glsl */ `\nvec3 mod289(vec3 x) { return x - floor(x * (1.0 / 289.0)) * 289.0; }\nvec4 mod289(vec4 x) { return x - floor(x * (1.0 / 289.0)) * 289.0; }\nvec4 permute(vec4 x) { return mod289(((x * 34.0) + 10.0) * x); }\nvec4 taylorInvSqrt(vec4 r) { return 1.79284291400159 - 0.85373472095314 * r; }\n\nfloat snoise(vec3 v) {\n const vec2 C = vec2(1.0 / 6.0, 1.0 / 3.0);\n const vec4 D = vec4(0.0, 0.5, 1.0, 2.0);\n\n vec3 i = floor(v + dot(v, C.yyy));\n vec3 x0 = v - i + dot(i, C.xxx);\n\n vec3 g = step(x0.yzx, x0.xyz);\n vec3 l = 1.0 - g;\n vec3 i1 = min(g.xyz, l.zxy);\n vec3 i2 = max(g.xyz, l.zxy);\n\n vec3 x1 = x0 - i1 + C.xxx;\n vec3 x2 = x0 - i2 + C.yyy;\n vec3 x3 = x0 - D.yyy;\n\n i = mod289(i);\n vec4 p = permute(permute(permute(\n i.z + vec4(0.0, i1.z, i2.z, 1.0))\n + i.y + vec4(0.0, i1.y, i2.y, 1.0))\n + i.x + vec4(0.0, i1.x, i2.x, 1.0));\n\n float n_ = 0.142857142857;\n vec3 ns = n_ * D.wyz - D.xzx;\n\n vec4 j = p - 49.0 * floor(p * ns.z * ns.z);\n vec4 x_ = floor(j * ns.z);\n vec4 y_ = floor(j - 7.0 * x_);\n\n vec4 x = x_ * ns.x + ns.yyyy;\n vec4 y = y_ * ns.x + ns.yyyy;\n vec4 h = 1.0 - abs(x) - abs(y);\n\n vec4 b0 = vec4(x.xy, y.xy);\n vec4 b1 = vec4(x.zw, y.zw);\n vec4 s0 = floor(b0) * 2.0 + 1.0;\n vec4 s1 = floor(b1) * 2.0 + 1.0;\n vec4 sh = -step(h, vec4(0.0));\n\n vec4 a0 = b0.xzyw + s0.xzyw * sh.xxyy;\n vec4 a1 = b1.xzyw + s1.xzyw * sh.zzww;\n\n vec3 p0 = vec3(a0.xy, h.x);\n vec3 p1 = vec3(a0.zw, h.y);\n vec3 p2 = vec3(a1.xy, h.z);\n vec3 p3 = vec3(a1.zw, h.w);\n\n vec4 norm = taylorInvSqrt(vec4(dot(p0, p0), dot(p1, p1), dot(p2, p2), dot(p3, p3)));\n p0 *= norm.x;\n p1 *= norm.y;\n p2 *= norm.z;\n p3 *= norm.w;\n\n vec4 m = max(0.5 - vec4(dot(x0, x0), dot(x1, x1), dot(x2, x2), dot(x3, x3)), 0.0);\n m = m * m;\n return 105.0 * dot(m * m, vec4(dot(p0, x0), dot(p1, x1), dot(p2, x2), dot(p3, x3)));\n}\n`;\n"]}
|