@esengine/procgen 1.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/dist/index.js ADDED
@@ -0,0 +1,1792 @@
1
+ var __defProp = Object.defineProperty;
2
+ var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
3
+ var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
4
+ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
5
+
6
+ // src/noise/PerlinNoise.ts
7
+ var _PerlinNoise = class _PerlinNoise {
8
+ /**
9
+ * @zh 创建 Perlin 噪声生成器
10
+ * @en Create Perlin noise generator
11
+ *
12
+ * @param seed - @zh 随机种子 @en Random seed
13
+ */
14
+ constructor(seed = 0) {
15
+ __publicField(this, "_perm");
16
+ __publicField(this, "_gradP");
17
+ this._perm = new Uint8Array(512);
18
+ this._gradP = new Float32Array(512 * 3);
19
+ this._seed(seed);
20
+ }
21
+ _seed(seed) {
22
+ const p = new Uint8Array(256);
23
+ for (let i = 0; i < 256; i++) {
24
+ p[i] = i;
25
+ }
26
+ let n = seed;
27
+ for (let i = 255; i > 0; i--) {
28
+ n = n * 16807 % 2147483647;
29
+ const j = n % (i + 1);
30
+ [p[i], p[j]] = [
31
+ p[j],
32
+ p[i]
33
+ ];
34
+ }
35
+ for (let i = 0; i < 512; i++) {
36
+ this._perm[i] = p[i & 255];
37
+ }
38
+ const grad3 = [
39
+ 1,
40
+ 1,
41
+ 0,
42
+ -1,
43
+ 1,
44
+ 0,
45
+ 1,
46
+ -1,
47
+ 0,
48
+ -1,
49
+ -1,
50
+ 0,
51
+ 1,
52
+ 0,
53
+ 1,
54
+ -1,
55
+ 0,
56
+ 1,
57
+ 1,
58
+ 0,
59
+ -1,
60
+ -1,
61
+ 0,
62
+ -1,
63
+ 0,
64
+ 1,
65
+ 1,
66
+ 0,
67
+ -1,
68
+ 1,
69
+ 0,
70
+ 1,
71
+ -1,
72
+ 0,
73
+ -1,
74
+ -1
75
+ ];
76
+ for (let i = 0; i < 512; i++) {
77
+ const gi = this._perm[i] % 12 * 3;
78
+ this._gradP[i * 3] = grad3[gi];
79
+ this._gradP[i * 3 + 1] = grad3[gi + 1];
80
+ this._gradP[i * 3 + 2] = grad3[gi + 2];
81
+ }
82
+ }
83
+ _fade(t) {
84
+ return t * t * t * (t * (t * 6 - 15) + 10);
85
+ }
86
+ _lerp(a, b, t) {
87
+ return a + t * (b - a);
88
+ }
89
+ _dot2(gi, x, y) {
90
+ return this._gradP[gi * 3] * x + this._gradP[gi * 3 + 1] * y;
91
+ }
92
+ _dot3(gi, x, y, z) {
93
+ return this._gradP[gi * 3] * x + this._gradP[gi * 3 + 1] * y + this._gradP[gi * 3 + 2] * z;
94
+ }
95
+ /**
96
+ * @zh 2D Perlin 噪声
97
+ * @en 2D Perlin noise
98
+ *
99
+ * @param x - @zh X 坐标 @en X coordinate
100
+ * @param y - @zh Y 坐标 @en Y coordinate
101
+ * @returns @zh 噪声值 [-1, 1] @en Noise value [-1, 1]
102
+ */
103
+ noise2D(x, y) {
104
+ const X = Math.floor(x) & 255;
105
+ const Y = Math.floor(y) & 255;
106
+ x -= Math.floor(x);
107
+ y -= Math.floor(y);
108
+ const u = this._fade(x);
109
+ const v = this._fade(y);
110
+ const A = this._perm[X] + Y;
111
+ const B = this._perm[X + 1] + Y;
112
+ return this._lerp(this._lerp(this._dot2(this._perm[A], x, y), this._dot2(this._perm[B], x - 1, y), u), this._lerp(this._dot2(this._perm[A + 1], x, y - 1), this._dot2(this._perm[B + 1], x - 1, y - 1), u), v);
113
+ }
114
+ /**
115
+ * @zh 3D Perlin 噪声
116
+ * @en 3D Perlin noise
117
+ *
118
+ * @param x - @zh X 坐标 @en X coordinate
119
+ * @param y - @zh Y 坐标 @en Y coordinate
120
+ * @param z - @zh Z 坐标 @en Z coordinate
121
+ * @returns @zh 噪声值 [-1, 1] @en Noise value [-1, 1]
122
+ */
123
+ noise3D(x, y, z) {
124
+ const X = Math.floor(x) & 255;
125
+ const Y = Math.floor(y) & 255;
126
+ const Z = Math.floor(z) & 255;
127
+ x -= Math.floor(x);
128
+ y -= Math.floor(y);
129
+ z -= Math.floor(z);
130
+ const u = this._fade(x);
131
+ const v = this._fade(y);
132
+ const w = this._fade(z);
133
+ const A = this._perm[X] + Y;
134
+ const AA = this._perm[A] + Z;
135
+ const AB = this._perm[A + 1] + Z;
136
+ const B = this._perm[X + 1] + Y;
137
+ const BA = this._perm[B] + Z;
138
+ const BB = this._perm[B + 1] + Z;
139
+ return this._lerp(this._lerp(this._lerp(this._dot3(this._perm[AA], x, y, z), this._dot3(this._perm[BA], x - 1, y, z), u), this._lerp(this._dot3(this._perm[AB], x, y - 1, z), this._dot3(this._perm[BB], x - 1, y - 1, z), u), v), this._lerp(this._lerp(this._dot3(this._perm[AA + 1], x, y, z - 1), this._dot3(this._perm[BA + 1], x - 1, y, z - 1), u), this._lerp(this._dot3(this._perm[AB + 1], x, y - 1, z - 1), this._dot3(this._perm[BB + 1], x - 1, y - 1, z - 1), u), v), w);
140
+ }
141
+ };
142
+ __name(_PerlinNoise, "PerlinNoise");
143
+ var PerlinNoise = _PerlinNoise;
144
+ function createPerlinNoise(seed = 0) {
145
+ return new PerlinNoise(seed);
146
+ }
147
+ __name(createPerlinNoise, "createPerlinNoise");
148
+
149
+ // src/noise/SimplexNoise.ts
150
+ var F2 = 0.5 * (Math.sqrt(3) - 1);
151
+ var G2 = (3 - Math.sqrt(3)) / 6;
152
+ var F3 = 1 / 3;
153
+ var G3 = 1 / 6;
154
+ var _SimplexNoise = class _SimplexNoise {
155
+ /**
156
+ * @zh 创建 Simplex 噪声生成器
157
+ * @en Create Simplex noise generator
158
+ *
159
+ * @param seed - @zh 随机种子 @en Random seed
160
+ */
161
+ constructor(seed = 0) {
162
+ __publicField(this, "_perm");
163
+ __publicField(this, "_permMod12");
164
+ this._perm = new Uint8Array(512);
165
+ this._permMod12 = new Uint8Array(512);
166
+ this._seed(seed);
167
+ }
168
+ _seed(seed) {
169
+ const p = new Uint8Array(256);
170
+ for (let i = 0; i < 256; i++) {
171
+ p[i] = i;
172
+ }
173
+ let n = seed;
174
+ for (let i = 255; i > 0; i--) {
175
+ n = n * 16807 % 2147483647;
176
+ const j = n % (i + 1);
177
+ [p[i], p[j]] = [
178
+ p[j],
179
+ p[i]
180
+ ];
181
+ }
182
+ for (let i = 0; i < 512; i++) {
183
+ this._perm[i] = p[i & 255];
184
+ this._permMod12[i] = this._perm[i] % 12;
185
+ }
186
+ }
187
+ /**
188
+ * @zh 2D Simplex 噪声
189
+ * @en 2D Simplex noise
190
+ *
191
+ * @param x - @zh X 坐标 @en X coordinate
192
+ * @param y - @zh Y 坐标 @en Y coordinate
193
+ * @returns @zh 噪声值 [-1, 1] @en Noise value [-1, 1]
194
+ */
195
+ noise2D(x, y) {
196
+ const grad3 = _SimplexNoise._grad3;
197
+ let n0 = 0, n1 = 0, n2 = 0;
198
+ const s = (x + y) * F2;
199
+ const i = Math.floor(x + s);
200
+ const j = Math.floor(y + s);
201
+ const t = (i + j) * G2;
202
+ const X0 = i - t;
203
+ const Y0 = j - t;
204
+ const x0 = x - X0;
205
+ const y0 = y - Y0;
206
+ let i1, j1;
207
+ if (x0 > y0) {
208
+ i1 = 1;
209
+ j1 = 0;
210
+ } else {
211
+ i1 = 0;
212
+ j1 = 1;
213
+ }
214
+ const x1 = x0 - i1 + G2;
215
+ const y1 = y0 - j1 + G2;
216
+ const x2 = x0 - 1 + 2 * G2;
217
+ const y2 = y0 - 1 + 2 * G2;
218
+ const ii = i & 255;
219
+ const jj = j & 255;
220
+ const gi0 = this._permMod12[ii + this._perm[jj]] * 3;
221
+ const gi1 = this._permMod12[ii + i1 + this._perm[jj + j1]] * 3;
222
+ const gi2 = this._permMod12[ii + 1 + this._perm[jj + 1]] * 3;
223
+ let t0 = 0.5 - x0 * x0 - y0 * y0;
224
+ if (t0 >= 0) {
225
+ t0 *= t0;
226
+ n0 = t0 * t0 * (grad3[gi0] * x0 + grad3[gi0 + 1] * y0);
227
+ }
228
+ let t1 = 0.5 - x1 * x1 - y1 * y1;
229
+ if (t1 >= 0) {
230
+ t1 *= t1;
231
+ n1 = t1 * t1 * (grad3[gi1] * x1 + grad3[gi1 + 1] * y1);
232
+ }
233
+ let t2 = 0.5 - x2 * x2 - y2 * y2;
234
+ if (t2 >= 0) {
235
+ t2 *= t2;
236
+ n2 = t2 * t2 * (grad3[gi2] * x2 + grad3[gi2 + 1] * y2);
237
+ }
238
+ return 70 * (n0 + n1 + n2);
239
+ }
240
+ /**
241
+ * @zh 3D Simplex 噪声
242
+ * @en 3D Simplex noise
243
+ *
244
+ * @param x - @zh X 坐标 @en X coordinate
245
+ * @param y - @zh Y 坐标 @en Y coordinate
246
+ * @param z - @zh Z 坐标 @en Z coordinate
247
+ * @returns @zh 噪声值 [-1, 1] @en Noise value [-1, 1]
248
+ */
249
+ noise3D(x, y, z) {
250
+ const grad3 = _SimplexNoise._grad3;
251
+ let n0 = 0, n1 = 0, n2 = 0, n3 = 0;
252
+ const s = (x + y + z) * F3;
253
+ const i = Math.floor(x + s);
254
+ const j = Math.floor(y + s);
255
+ const k = Math.floor(z + s);
256
+ const t = (i + j + k) * G3;
257
+ const X0 = i - t;
258
+ const Y0 = j - t;
259
+ const Z0 = k - t;
260
+ const x0 = x - X0;
261
+ const y0 = y - Y0;
262
+ const z0 = z - Z0;
263
+ let i1, j1, k1;
264
+ let i2, j2, k2;
265
+ if (x0 >= y0) {
266
+ if (y0 >= z0) {
267
+ i1 = 1;
268
+ j1 = 0;
269
+ k1 = 0;
270
+ i2 = 1;
271
+ j2 = 1;
272
+ k2 = 0;
273
+ } else if (x0 >= z0) {
274
+ i1 = 1;
275
+ j1 = 0;
276
+ k1 = 0;
277
+ i2 = 1;
278
+ j2 = 0;
279
+ k2 = 1;
280
+ } else {
281
+ i1 = 0;
282
+ j1 = 0;
283
+ k1 = 1;
284
+ i2 = 1;
285
+ j2 = 0;
286
+ k2 = 1;
287
+ }
288
+ } else {
289
+ if (y0 < z0) {
290
+ i1 = 0;
291
+ j1 = 0;
292
+ k1 = 1;
293
+ i2 = 0;
294
+ j2 = 1;
295
+ k2 = 1;
296
+ } else if (x0 < z0) {
297
+ i1 = 0;
298
+ j1 = 1;
299
+ k1 = 0;
300
+ i2 = 0;
301
+ j2 = 1;
302
+ k2 = 1;
303
+ } else {
304
+ i1 = 0;
305
+ j1 = 1;
306
+ k1 = 0;
307
+ i2 = 1;
308
+ j2 = 1;
309
+ k2 = 0;
310
+ }
311
+ }
312
+ const x1 = x0 - i1 + G3;
313
+ const y1 = y0 - j1 + G3;
314
+ const z1 = z0 - k1 + G3;
315
+ const x2 = x0 - i2 + 2 * G3;
316
+ const y2 = y0 - j2 + 2 * G3;
317
+ const z2 = z0 - k2 + 2 * G3;
318
+ const x3 = x0 - 1 + 3 * G3;
319
+ const y3 = y0 - 1 + 3 * G3;
320
+ const z3 = z0 - 1 + 3 * G3;
321
+ const ii = i & 255;
322
+ const jj = j & 255;
323
+ const kk = k & 255;
324
+ const gi0 = this._permMod12[ii + this._perm[jj + this._perm[kk]]] * 3;
325
+ const gi1 = this._permMod12[ii + i1 + this._perm[jj + j1 + this._perm[kk + k1]]] * 3;
326
+ const gi2 = this._permMod12[ii + i2 + this._perm[jj + j2 + this._perm[kk + k2]]] * 3;
327
+ const gi3 = this._permMod12[ii + 1 + this._perm[jj + 1 + this._perm[kk + 1]]] * 3;
328
+ let t0 = 0.6 - x0 * x0 - y0 * y0 - z0 * z0;
329
+ if (t0 >= 0) {
330
+ t0 *= t0;
331
+ n0 = t0 * t0 * (grad3[gi0] * x0 + grad3[gi0 + 1] * y0 + grad3[gi0 + 2] * z0);
332
+ }
333
+ let t1 = 0.6 - x1 * x1 - y1 * y1 - z1 * z1;
334
+ if (t1 >= 0) {
335
+ t1 *= t1;
336
+ n1 = t1 * t1 * (grad3[gi1] * x1 + grad3[gi1 + 1] * y1 + grad3[gi1 + 2] * z1);
337
+ }
338
+ let t2 = 0.6 - x2 * x2 - y2 * y2 - z2 * z2;
339
+ if (t2 >= 0) {
340
+ t2 *= t2;
341
+ n2 = t2 * t2 * (grad3[gi2] * x2 + grad3[gi2 + 1] * y2 + grad3[gi2 + 2] * z2);
342
+ }
343
+ let t3 = 0.6 - x3 * x3 - y3 * y3 - z3 * z3;
344
+ if (t3 >= 0) {
345
+ t3 *= t3;
346
+ n3 = t3 * t3 * (grad3[gi3] * x3 + grad3[gi3 + 1] * y3 + grad3[gi3 + 2] * z3);
347
+ }
348
+ return 32 * (n0 + n1 + n2 + n3);
349
+ }
350
+ };
351
+ __name(_SimplexNoise, "SimplexNoise");
352
+ __publicField(_SimplexNoise, "_grad3", new Float32Array([
353
+ 1,
354
+ 1,
355
+ 0,
356
+ -1,
357
+ 1,
358
+ 0,
359
+ 1,
360
+ -1,
361
+ 0,
362
+ -1,
363
+ -1,
364
+ 0,
365
+ 1,
366
+ 0,
367
+ 1,
368
+ -1,
369
+ 0,
370
+ 1,
371
+ 1,
372
+ 0,
373
+ -1,
374
+ -1,
375
+ 0,
376
+ -1,
377
+ 0,
378
+ 1,
379
+ 1,
380
+ 0,
381
+ -1,
382
+ 1,
383
+ 0,
384
+ 1,
385
+ -1,
386
+ 0,
387
+ -1,
388
+ -1
389
+ ]));
390
+ var SimplexNoise = _SimplexNoise;
391
+ function createSimplexNoise(seed = 0) {
392
+ return new SimplexNoise(seed);
393
+ }
394
+ __name(createSimplexNoise, "createSimplexNoise");
395
+
396
+ // src/noise/WorleyNoise.ts
397
+ var _WorleyNoise = class _WorleyNoise {
398
+ /**
399
+ * @zh 创建 Worley 噪声生成器
400
+ * @en Create Worley noise generator
401
+ *
402
+ * @param seed - @zh 随机种子 @en Random seed
403
+ * @param distanceFunc - @zh 距离函数 @en Distance function
404
+ */
405
+ constructor(seed = 0, distanceFunc = "euclidean") {
406
+ __publicField(this, "_seed");
407
+ __publicField(this, "_distanceFunc");
408
+ this._seed = seed;
409
+ this._distanceFunc = distanceFunc;
410
+ }
411
+ _hash(x, y, z = 0) {
412
+ let h = this._seed;
413
+ h ^= x * 374761393;
414
+ h ^= y * 668265263;
415
+ h ^= z * 1274126177;
416
+ h = Math.imul(h ^ h >>> 13, 1274126177);
417
+ return h;
418
+ }
419
+ _randomPoint(cellX, cellY, index) {
420
+ const h1 = this._hash(cellX, cellY, index);
421
+ const h2 = this._hash(cellX, cellY, index + 1e3);
422
+ return {
423
+ x: cellX + (h1 & 65535) / 65536,
424
+ y: cellY + (h2 & 65535) / 65536
425
+ };
426
+ }
427
+ _randomPoint3D(cellX, cellY, cellZ, index) {
428
+ const h1 = this._hash(cellX, cellY, cellZ * 1e3 + index);
429
+ const h2 = this._hash(cellX, cellY, cellZ * 1e3 + index + 1e3);
430
+ const h3 = this._hash(cellX, cellY, cellZ * 1e3 + index + 2e3);
431
+ return {
432
+ x: cellX + (h1 & 65535) / 65536,
433
+ y: cellY + (h2 & 65535) / 65536,
434
+ z: cellZ + (h3 & 65535) / 65536
435
+ };
436
+ }
437
+ _distance2D(x1, y1, x2, y2) {
438
+ const dx = x2 - x1;
439
+ const dy = y2 - y1;
440
+ switch (this._distanceFunc) {
441
+ case "manhattan":
442
+ return Math.abs(dx) + Math.abs(dy);
443
+ case "chebyshev":
444
+ return Math.max(Math.abs(dx), Math.abs(dy));
445
+ case "euclidean":
446
+ default:
447
+ return Math.sqrt(dx * dx + dy * dy);
448
+ }
449
+ }
450
+ _distance3D(x1, y1, z1, x2, y2, z2) {
451
+ const dx = x2 - x1;
452
+ const dy = y2 - y1;
453
+ const dz = z2 - z1;
454
+ switch (this._distanceFunc) {
455
+ case "manhattan":
456
+ return Math.abs(dx) + Math.abs(dy) + Math.abs(dz);
457
+ case "chebyshev":
458
+ return Math.max(Math.abs(dx), Math.abs(dy), Math.abs(dz));
459
+ case "euclidean":
460
+ default:
461
+ return Math.sqrt(dx * dx + dy * dy + dz * dz);
462
+ }
463
+ }
464
+ /**
465
+ * @zh 2D Worley 噪声
466
+ * @en 2D Worley noise
467
+ *
468
+ * @param x - @zh X 坐标 @en X coordinate
469
+ * @param y - @zh Y 坐标 @en Y coordinate
470
+ * @param pointsPerCell - @zh 每个单元格的点数 @en Points per cell
471
+ * @returns @zh 到最近点的距离 [0, ~1.4] @en Distance to nearest point [0, ~1.4]
472
+ */
473
+ noise2D(x, y, pointsPerCell = 1) {
474
+ const cellX = Math.floor(x);
475
+ const cellY = Math.floor(y);
476
+ let minDist = Infinity;
477
+ for (let dx = -1; dx <= 1; dx++) {
478
+ for (let dy = -1; dy <= 1; dy++) {
479
+ const cx = cellX + dx;
480
+ const cy = cellY + dy;
481
+ for (let i = 0; i < pointsPerCell; i++) {
482
+ const point = this._randomPoint(cx, cy, i);
483
+ const dist = this._distance2D(x, y, point.x, point.y);
484
+ minDist = Math.min(minDist, dist);
485
+ }
486
+ }
487
+ }
488
+ return minDist;
489
+ }
490
+ /**
491
+ * @zh 3D Worley 噪声
492
+ * @en 3D Worley noise
493
+ *
494
+ * @param x - @zh X 坐标 @en X coordinate
495
+ * @param y - @zh Y 坐标 @en Y coordinate
496
+ * @param z - @zh Z 坐标 @en Z coordinate
497
+ * @param pointsPerCell - @zh 每个单元格的点数 @en Points per cell
498
+ * @returns @zh 到最近点的距离 @en Distance to nearest point
499
+ */
500
+ noise3D(x, y, z, pointsPerCell = 1) {
501
+ const cellX = Math.floor(x);
502
+ const cellY = Math.floor(y);
503
+ const cellZ = Math.floor(z);
504
+ let minDist = Infinity;
505
+ for (let dx = -1; dx <= 1; dx++) {
506
+ for (let dy = -1; dy <= 1; dy++) {
507
+ for (let dz = -1; dz <= 1; dz++) {
508
+ const cx = cellX + dx;
509
+ const cy = cellY + dy;
510
+ const cz = cellZ + dz;
511
+ for (let i = 0; i < pointsPerCell; i++) {
512
+ const point = this._randomPoint3D(cx, cy, cz, i);
513
+ const dist = this._distance3D(x, y, z, point.x, point.y, point.z);
514
+ minDist = Math.min(minDist, dist);
515
+ }
516
+ }
517
+ }
518
+ }
519
+ return minDist;
520
+ }
521
+ /**
522
+ * @zh 获取到第 N 近点的距离(用于更复杂的纹理)
523
+ * @en Get distance to Nth nearest point (for more complex textures)
524
+ *
525
+ * @param x - @zh X 坐标 @en X coordinate
526
+ * @param y - @zh Y 坐标 @en Y coordinate
527
+ * @param n - @zh 第 N 近 (1 = 最近) @en Nth nearest (1 = nearest)
528
+ * @returns @zh 距离值 @en Distance value
529
+ */
530
+ nthNearest2D(x, y, n = 1) {
531
+ const cellX = Math.floor(x);
532
+ const cellY = Math.floor(y);
533
+ const distances = [];
534
+ for (let dx = -1; dx <= 1; dx++) {
535
+ for (let dy = -1; dy <= 1; dy++) {
536
+ const cx = cellX + dx;
537
+ const cy = cellY + dy;
538
+ const point = this._randomPoint(cx, cy, 0);
539
+ distances.push(this._distance2D(x, y, point.x, point.y));
540
+ }
541
+ }
542
+ distances.sort((a, b) => a - b);
543
+ return distances[Math.min(n - 1, distances.length - 1)];
544
+ }
545
+ };
546
+ __name(_WorleyNoise, "WorleyNoise");
547
+ var WorleyNoise = _WorleyNoise;
548
+ function createWorleyNoise(seed = 0, distanceFunc = "euclidean") {
549
+ return new WorleyNoise(seed, distanceFunc);
550
+ }
551
+ __name(createWorleyNoise, "createWorleyNoise");
552
+
553
+ // src/noise/FBM.ts
554
+ var DEFAULT_CONFIG = {
555
+ octaves: 6,
556
+ lacunarity: 2,
557
+ persistence: 0.5,
558
+ frequency: 1,
559
+ amplitude: 1
560
+ };
561
+ var _FBM = class _FBM {
562
+ /**
563
+ * @zh 创建 FBM 噪声生成器
564
+ * @en Create FBM noise generator
565
+ *
566
+ * @param noise - @zh 基础噪声函数 @en Base noise function
567
+ * @param config - @zh 配置 @en Configuration
568
+ */
569
+ constructor(noise, config) {
570
+ __publicField(this, "_noise");
571
+ __publicField(this, "_config");
572
+ this._noise = noise;
573
+ this._config = {
574
+ ...DEFAULT_CONFIG,
575
+ ...config
576
+ };
577
+ }
578
+ /**
579
+ * @zh 2D FBM 噪声
580
+ * @en 2D FBM noise
581
+ *
582
+ * @param x - @zh X 坐标 @en X coordinate
583
+ * @param y - @zh Y 坐标 @en Y coordinate
584
+ * @returns @zh 噪声值 @en Noise value
585
+ */
586
+ noise2D(x, y) {
587
+ let value = 0;
588
+ let frequency = this._config.frequency;
589
+ let amplitude = this._config.amplitude;
590
+ let maxValue = 0;
591
+ for (let i = 0; i < this._config.octaves; i++) {
592
+ value += this._noise.noise2D(x * frequency, y * frequency) * amplitude;
593
+ maxValue += amplitude;
594
+ amplitude *= this._config.persistence;
595
+ frequency *= this._config.lacunarity;
596
+ }
597
+ return value / maxValue;
598
+ }
599
+ /**
600
+ * @zh 3D FBM 噪声
601
+ * @en 3D FBM noise
602
+ *
603
+ * @param x - @zh X 坐标 @en X coordinate
604
+ * @param y - @zh Y 坐标 @en Y coordinate
605
+ * @param z - @zh Z 坐标 @en Z coordinate
606
+ * @returns @zh 噪声值 @en Noise value
607
+ */
608
+ noise3D(x, y, z) {
609
+ if (!this._noise.noise3D) {
610
+ throw new Error("Base noise does not support 3D");
611
+ }
612
+ let value = 0;
613
+ let frequency = this._config.frequency;
614
+ let amplitude = this._config.amplitude;
615
+ let maxValue = 0;
616
+ for (let i = 0; i < this._config.octaves; i++) {
617
+ value += this._noise.noise3D(x * frequency, y * frequency, z * frequency) * amplitude;
618
+ maxValue += amplitude;
619
+ amplitude *= this._config.persistence;
620
+ frequency *= this._config.lacunarity;
621
+ }
622
+ return value / maxValue;
623
+ }
624
+ /**
625
+ * @zh Ridged FBM(脊状,适合山脉)
626
+ * @en Ridged FBM (suitable for mountains)
627
+ */
628
+ ridged2D(x, y) {
629
+ let value = 0;
630
+ let frequency = this._config.frequency;
631
+ let amplitude = this._config.amplitude;
632
+ let weight = 1;
633
+ for (let i = 0; i < this._config.octaves; i++) {
634
+ let signal = this._noise.noise2D(x * frequency, y * frequency);
635
+ signal = 1 - Math.abs(signal);
636
+ signal *= signal;
637
+ signal *= weight;
638
+ weight = Math.max(0, Math.min(1, signal * 2));
639
+ value += signal * amplitude;
640
+ frequency *= this._config.lacunarity;
641
+ amplitude *= this._config.persistence;
642
+ }
643
+ return value;
644
+ }
645
+ /**
646
+ * @zh Turbulence(湍流,使用绝对值)
647
+ * @en Turbulence (using absolute value)
648
+ */
649
+ turbulence2D(x, y) {
650
+ let value = 0;
651
+ let frequency = this._config.frequency;
652
+ let amplitude = this._config.amplitude;
653
+ let maxValue = 0;
654
+ for (let i = 0; i < this._config.octaves; i++) {
655
+ value += Math.abs(this._noise.noise2D(x * frequency, y * frequency)) * amplitude;
656
+ maxValue += amplitude;
657
+ amplitude *= this._config.persistence;
658
+ frequency *= this._config.lacunarity;
659
+ }
660
+ return value / maxValue;
661
+ }
662
+ /**
663
+ * @zh Billowed(膨胀,适合云朵)
664
+ * @en Billowed (suitable for clouds)
665
+ */
666
+ billowed2D(x, y) {
667
+ let value = 0;
668
+ let frequency = this._config.frequency;
669
+ let amplitude = this._config.amplitude;
670
+ let maxValue = 0;
671
+ for (let i = 0; i < this._config.octaves; i++) {
672
+ const n = this._noise.noise2D(x * frequency, y * frequency);
673
+ value += (Math.abs(n) * 2 - 1) * amplitude;
674
+ maxValue += amplitude;
675
+ amplitude *= this._config.persistence;
676
+ frequency *= this._config.lacunarity;
677
+ }
678
+ return value / maxValue;
679
+ }
680
+ };
681
+ __name(_FBM, "FBM");
682
+ var FBM = _FBM;
683
+ function createFBM(noise, config) {
684
+ return new FBM(noise, config);
685
+ }
686
+ __name(createFBM, "createFBM");
687
+
688
+ // src/random/SeededRandom.ts
689
+ var _SeededRandom = class _SeededRandom {
690
+ /**
691
+ * @zh 创建种子随机数生成器
692
+ * @en Create seeded random number generator
693
+ *
694
+ * @param seed - @zh 随机种子 @en Random seed
695
+ */
696
+ constructor(seed = Date.now()) {
697
+ __publicField(this, "_s0");
698
+ __publicField(this, "_s1");
699
+ __publicField(this, "_initialS0");
700
+ __publicField(this, "_initialS1");
701
+ let h = seed | 0;
702
+ h = Math.imul(h ^ h >>> 16, 2246822507);
703
+ h = Math.imul(h ^ h >>> 13, 3266489909);
704
+ h ^= h >>> 16;
705
+ this._s0 = h >>> 0;
706
+ this._s1 = h * 2654435769 >>> 0;
707
+ if (this._s0 === 0) this._s0 = 1;
708
+ if (this._s1 === 0) this._s1 = 1;
709
+ this._initialS0 = this._s0;
710
+ this._initialS1 = this._s1;
711
+ for (let i = 0; i < 10; i++) {
712
+ this.next();
713
+ }
714
+ }
715
+ /**
716
+ * @zh 重置到初始状态
717
+ * @en Reset to initial state
718
+ */
719
+ reset() {
720
+ this._s0 = this._initialS0;
721
+ this._s1 = this._initialS1;
722
+ for (let i = 0; i < 10; i++) {
723
+ this.next();
724
+ }
725
+ }
726
+ /**
727
+ * @zh 生成下一个随机数 [0, 1)
728
+ * @en Generate next random number [0, 1)
729
+ */
730
+ next() {
731
+ let s1 = this._s0;
732
+ const s0 = this._s1;
733
+ this._s0 = s0;
734
+ s1 ^= s1 << 23;
735
+ s1 ^= s1 >>> 17;
736
+ s1 ^= s0;
737
+ s1 ^= s0 >>> 26;
738
+ this._s1 = s1;
739
+ return (this._s0 + this._s1 >>> 0) / 4294967296;
740
+ }
741
+ /**
742
+ * @zh 生成整数 [min, max]
743
+ * @en Generate integer [min, max]
744
+ */
745
+ nextInt(min, max) {
746
+ return Math.floor(this.next() * (max - min + 1)) + min;
747
+ }
748
+ /**
749
+ * @zh 生成浮点数 [min, max)
750
+ * @en Generate float [min, max)
751
+ */
752
+ nextFloat(min, max) {
753
+ return this.next() * (max - min) + min;
754
+ }
755
+ /**
756
+ * @zh 生成布尔值
757
+ * @en Generate boolean
758
+ *
759
+ * @param probability - @zh 为 true 的概率 [0, 1] @en Probability of true [0, 1]
760
+ */
761
+ nextBool(probability = 0.5) {
762
+ return this.next() < probability;
763
+ }
764
+ /**
765
+ * @zh 生成正态分布随机数 (Box-Muller 变换)
766
+ * @en Generate normally distributed random number (Box-Muller transform)
767
+ *
768
+ * @param mean - @zh 均值 @en Mean
769
+ * @param stdDev - @zh 标准差 @en Standard deviation
770
+ */
771
+ nextGaussian(mean = 0, stdDev = 1) {
772
+ const u1 = this.next();
773
+ const u2 = this.next();
774
+ const z0 = Math.sqrt(-2 * Math.log(u1)) * Math.cos(2 * Math.PI * u2);
775
+ return z0 * stdDev + mean;
776
+ }
777
+ /**
778
+ * @zh 生成指数分布随机数
779
+ * @en Generate exponentially distributed random number
780
+ *
781
+ * @param lambda - @zh 率参数 @en Rate parameter
782
+ */
783
+ nextExponential(lambda = 1) {
784
+ return -Math.log(1 - this.next()) / lambda;
785
+ }
786
+ /**
787
+ * @zh 在圆内生成均匀分布的随机点
788
+ * @en Generate uniformly distributed random point in circle
789
+ *
790
+ * @param radius - @zh 半径 @en Radius
791
+ */
792
+ nextPointInCircle(radius = 1) {
793
+ const r = Math.sqrt(this.next()) * radius;
794
+ const theta = this.next() * 2 * Math.PI;
795
+ return {
796
+ x: r * Math.cos(theta),
797
+ y: r * Math.sin(theta)
798
+ };
799
+ }
800
+ /**
801
+ * @zh 在圆环上生成随机点
802
+ * @en Generate random point on circle
803
+ *
804
+ * @param radius - @zh 半径 @en Radius
805
+ */
806
+ nextPointOnCircle(radius = 1) {
807
+ const theta = this.next() * 2 * Math.PI;
808
+ return {
809
+ x: radius * Math.cos(theta),
810
+ y: radius * Math.sin(theta)
811
+ };
812
+ }
813
+ /**
814
+ * @zh 在球内生成均匀分布的随机点
815
+ * @en Generate uniformly distributed random point in sphere
816
+ *
817
+ * @param radius - @zh 半径 @en Radius
818
+ */
819
+ nextPointInSphere(radius = 1) {
820
+ const r = Math.cbrt(this.next()) * radius;
821
+ const theta = this.next() * 2 * Math.PI;
822
+ const phi = Math.acos(2 * this.next() - 1);
823
+ return {
824
+ x: r * Math.sin(phi) * Math.cos(theta),
825
+ y: r * Math.sin(phi) * Math.sin(theta),
826
+ z: r * Math.cos(phi)
827
+ };
828
+ }
829
+ /**
830
+ * @zh 生成随机方向向量
831
+ * @en Generate random direction vector
832
+ */
833
+ nextDirection2D() {
834
+ const theta = this.next() * 2 * Math.PI;
835
+ return {
836
+ x: Math.cos(theta),
837
+ y: Math.sin(theta)
838
+ };
839
+ }
840
+ };
841
+ __name(_SeededRandom, "SeededRandom");
842
+ var SeededRandom = _SeededRandom;
843
+ function createSeededRandom(seed) {
844
+ return new SeededRandom(seed);
845
+ }
846
+ __name(createSeededRandom, "createSeededRandom");
847
+
848
+ // src/random/WeightedRandom.ts
849
+ var _WeightedRandom = class _WeightedRandom {
850
+ /**
851
+ * @zh 创建加权随机选择器
852
+ * @en Create weighted random selector
853
+ *
854
+ * @param items - @zh 加权项数组 @en Array of weighted items
855
+ */
856
+ constructor(items) {
857
+ __publicField(this, "_items");
858
+ __publicField(this, "_cumulativeWeights");
859
+ __publicField(this, "_totalWeight");
860
+ if (items.length === 0) {
861
+ throw new Error("Items array cannot be empty");
862
+ }
863
+ this._items = [
864
+ ...items
865
+ ];
866
+ this._cumulativeWeights = [];
867
+ let total = 0;
868
+ for (const item of this._items) {
869
+ if (item.weight <= 0) {
870
+ throw new Error("Weights must be positive");
871
+ }
872
+ total += item.weight;
873
+ this._cumulativeWeights.push(total);
874
+ }
875
+ this._totalWeight = total;
876
+ }
877
+ /**
878
+ * @zh 随机选择一个项目
879
+ * @en Randomly select an item
880
+ *
881
+ * @param rng - @zh 随机数生成器 @en Random number generator
882
+ */
883
+ pick(rng) {
884
+ const r = rng.next() * this._totalWeight;
885
+ let left = 0;
886
+ let right = this._cumulativeWeights.length - 1;
887
+ while (left < right) {
888
+ const mid = left + right >>> 1;
889
+ if (this._cumulativeWeights[mid] < r) {
890
+ left = mid + 1;
891
+ } else {
892
+ right = mid;
893
+ }
894
+ }
895
+ return this._items[left].value;
896
+ }
897
+ /**
898
+ * @zh 使用 Math.random 选择
899
+ * @en Pick using Math.random
900
+ */
901
+ pickRandom() {
902
+ return this.pick({
903
+ next: /* @__PURE__ */ __name(() => Math.random(), "next")
904
+ });
905
+ }
906
+ /**
907
+ * @zh 获取项目的选中概率
908
+ * @en Get selection probability of an item
909
+ */
910
+ getProbability(index) {
911
+ if (index < 0 || index >= this._items.length) {
912
+ throw new Error("Index out of bounds");
913
+ }
914
+ return this._items[index].weight / this._totalWeight;
915
+ }
916
+ /**
917
+ * @zh 获取所有项目数量
918
+ * @en Get total item count
919
+ */
920
+ get size() {
921
+ return this._items.length;
922
+ }
923
+ /**
924
+ * @zh 获取总权重
925
+ * @en Get total weight
926
+ */
927
+ get totalWeight() {
928
+ return this._totalWeight;
929
+ }
930
+ };
931
+ __name(_WeightedRandom, "WeightedRandom");
932
+ var WeightedRandom = _WeightedRandom;
933
+ function weightedPick(items, rng) {
934
+ if (items.length === 0) {
935
+ throw new Error("Items array cannot be empty");
936
+ }
937
+ let totalWeight = 0;
938
+ for (const item of items) {
939
+ totalWeight += item.weight;
940
+ }
941
+ let r = rng.next() * totalWeight;
942
+ for (const item of items) {
943
+ r -= item.weight;
944
+ if (r <= 0) {
945
+ return item.value;
946
+ }
947
+ }
948
+ return items[items.length - 1].value;
949
+ }
950
+ __name(weightedPick, "weightedPick");
951
+ function weightedPickFromMap(weights, rng) {
952
+ const items = [];
953
+ for (const key in weights) {
954
+ items.push({
955
+ value: key,
956
+ weight: weights[key]
957
+ });
958
+ }
959
+ return weightedPick(items, rng);
960
+ }
961
+ __name(weightedPickFromMap, "weightedPickFromMap");
962
+ function createWeightedRandom(items) {
963
+ return new WeightedRandom(items);
964
+ }
965
+ __name(createWeightedRandom, "createWeightedRandom");
966
+
967
+ // src/random/Shuffle.ts
968
+ function shuffle(array, rng) {
969
+ for (let i = array.length - 1; i > 0; i--) {
970
+ const j = Math.floor(rng.next() * (i + 1));
971
+ [array[i], array[j]] = [
972
+ array[j],
973
+ array[i]
974
+ ];
975
+ }
976
+ return array;
977
+ }
978
+ __name(shuffle, "shuffle");
979
+ function shuffleCopy(array, rng) {
980
+ return shuffle([
981
+ ...array
982
+ ], rng);
983
+ }
984
+ __name(shuffleCopy, "shuffleCopy");
985
+ function pickOne(array, rng) {
986
+ if (array.length === 0) {
987
+ throw new Error("Cannot pick from empty array");
988
+ }
989
+ return array[Math.floor(rng.next() * array.length)];
990
+ }
991
+ __name(pickOne, "pickOne");
992
+ function sample(array, count, rng) {
993
+ if (count > array.length) {
994
+ throw new Error("Sample count exceeds array length");
995
+ }
996
+ if (count === array.length) {
997
+ return shuffleCopy(array, rng);
998
+ }
999
+ if (count < array.length / 2) {
1000
+ const result = [];
1001
+ const indices = /* @__PURE__ */ new Set();
1002
+ while (result.length < count) {
1003
+ const index = Math.floor(rng.next() * array.length);
1004
+ if (!indices.has(index)) {
1005
+ indices.add(index);
1006
+ result.push(array[index]);
1007
+ }
1008
+ }
1009
+ return result;
1010
+ }
1011
+ return shuffleCopy(array, rng).slice(0, count);
1012
+ }
1013
+ __name(sample, "sample");
1014
+ function sampleWithReplacement(array, count, rng) {
1015
+ if (array.length === 0) {
1016
+ throw new Error("Cannot sample from empty array");
1017
+ }
1018
+ const result = [];
1019
+ for (let i = 0; i < count; i++) {
1020
+ result.push(pickOne(array, rng));
1021
+ }
1022
+ return result;
1023
+ }
1024
+ __name(sampleWithReplacement, "sampleWithReplacement");
1025
+ function randomIntegers(min, max, count, rng) {
1026
+ const range = max - min + 1;
1027
+ if (count > range) {
1028
+ throw new Error("Count exceeds range");
1029
+ }
1030
+ const numbers = [];
1031
+ for (let i = min; i <= max; i++) {
1032
+ numbers.push(i);
1033
+ }
1034
+ return sample(numbers, count, rng);
1035
+ }
1036
+ __name(randomIntegers, "randomIntegers");
1037
+ function weightedSample(items, weights, count, rng) {
1038
+ if (items.length !== weights.length) {
1039
+ throw new Error("Items and weights must have same length");
1040
+ }
1041
+ if (count > items.length) {
1042
+ throw new Error("Sample count exceeds array length");
1043
+ }
1044
+ const result = [];
1045
+ const remaining = [
1046
+ ...items
1047
+ ];
1048
+ const remainingWeights = [
1049
+ ...weights
1050
+ ];
1051
+ for (let i = 0; i < count; i++) {
1052
+ let totalWeight = 0;
1053
+ for (const w of remainingWeights) {
1054
+ totalWeight += w;
1055
+ }
1056
+ let r = rng.next() * totalWeight;
1057
+ let selectedIndex = 0;
1058
+ for (let j = 0; j < remainingWeights.length; j++) {
1059
+ r -= remainingWeights[j];
1060
+ if (r <= 0) {
1061
+ selectedIndex = j;
1062
+ break;
1063
+ }
1064
+ }
1065
+ result.push(remaining[selectedIndex]);
1066
+ remaining.splice(selectedIndex, 1);
1067
+ remainingWeights.splice(selectedIndex, 1);
1068
+ }
1069
+ return result;
1070
+ }
1071
+ __name(weightedSample, "weightedSample");
1072
+
1073
+ // src/nodes/ProcGenNodes.ts
1074
+ var noiseCache = /* @__PURE__ */ new Map();
1075
+ function getPerlinNoise(seed) {
1076
+ const key = `perlin_${seed}`;
1077
+ if (!noiseCache.has(key)) {
1078
+ noiseCache.set(key, new PerlinNoise(seed));
1079
+ }
1080
+ return noiseCache.get(key);
1081
+ }
1082
+ __name(getPerlinNoise, "getPerlinNoise");
1083
+ function getSimplexNoise(seed) {
1084
+ const key = `simplex_${seed}`;
1085
+ if (!noiseCache.has(key)) {
1086
+ noiseCache.set(key, new SimplexNoise(seed));
1087
+ }
1088
+ return noiseCache.get(key);
1089
+ }
1090
+ __name(getSimplexNoise, "getSimplexNoise");
1091
+ function getWorleyNoise(seed) {
1092
+ const key = `worley_${seed}`;
1093
+ if (!noiseCache.has(key)) {
1094
+ noiseCache.set(key, new WorleyNoise(seed));
1095
+ }
1096
+ return noiseCache.get(key);
1097
+ }
1098
+ __name(getWorleyNoise, "getWorleyNoise");
1099
+ var SampleNoise2DTemplate = {
1100
+ type: "SampleNoise2D",
1101
+ title: "Sample Noise 2D",
1102
+ category: "math",
1103
+ description: "Sample 2D noise at coordinates / \u5728\u5750\u6807\u5904\u91C7\u6837 2D \u566A\u58F0",
1104
+ keywords: [
1105
+ "noise",
1106
+ "perlin",
1107
+ "simplex",
1108
+ "random",
1109
+ "procedural"
1110
+ ],
1111
+ menuPath: [
1112
+ "Procedural",
1113
+ "Noise",
1114
+ "Sample Noise 2D"
1115
+ ],
1116
+ isPure: true,
1117
+ inputs: [
1118
+ {
1119
+ name: "x",
1120
+ displayName: "X",
1121
+ type: "float"
1122
+ },
1123
+ {
1124
+ name: "y",
1125
+ displayName: "Y",
1126
+ type: "float"
1127
+ },
1128
+ {
1129
+ name: "seed",
1130
+ displayName: "Seed",
1131
+ type: "int"
1132
+ },
1133
+ {
1134
+ name: "noiseType",
1135
+ displayName: "Type",
1136
+ type: "string"
1137
+ }
1138
+ ],
1139
+ outputs: [
1140
+ {
1141
+ name: "value",
1142
+ displayName: "Value",
1143
+ type: "float"
1144
+ }
1145
+ ],
1146
+ color: "#9c27b0"
1147
+ };
1148
+ var _SampleNoise2DExecutor = class _SampleNoise2DExecutor {
1149
+ execute(node, context) {
1150
+ const ctx = context;
1151
+ const x = ctx.evaluateInput(node.id, "x", 0);
1152
+ const y = ctx.evaluateInput(node.id, "y", 0);
1153
+ const seed = ctx.evaluateInput(node.id, "seed", 0);
1154
+ const noiseType = ctx.evaluateInput(node.id, "noiseType", "perlin");
1155
+ let value = 0;
1156
+ switch (noiseType.toLowerCase()) {
1157
+ case "simplex":
1158
+ value = getSimplexNoise(seed).noise2D(x, y);
1159
+ break;
1160
+ case "worley":
1161
+ value = getWorleyNoise(seed).noise2D(x, y);
1162
+ break;
1163
+ case "perlin":
1164
+ default:
1165
+ value = getPerlinNoise(seed).noise2D(x, y);
1166
+ break;
1167
+ }
1168
+ return {
1169
+ outputs: {
1170
+ value
1171
+ }
1172
+ };
1173
+ }
1174
+ };
1175
+ __name(_SampleNoise2DExecutor, "SampleNoise2DExecutor");
1176
+ var SampleNoise2DExecutor = _SampleNoise2DExecutor;
1177
+ var SampleFBMTemplate = {
1178
+ type: "SampleFBM",
1179
+ title: "Sample FBM",
1180
+ category: "math",
1181
+ description: "Sample Fractal Brownian Motion noise / \u91C7\u6837\u5206\u5F62\u5E03\u6717\u8FD0\u52A8\u566A\u58F0",
1182
+ keywords: [
1183
+ "noise",
1184
+ "fbm",
1185
+ "fractal",
1186
+ "octave",
1187
+ "terrain"
1188
+ ],
1189
+ menuPath: [
1190
+ "Procedural",
1191
+ "Noise",
1192
+ "Sample FBM"
1193
+ ],
1194
+ isPure: true,
1195
+ inputs: [
1196
+ {
1197
+ name: "x",
1198
+ displayName: "X",
1199
+ type: "float"
1200
+ },
1201
+ {
1202
+ name: "y",
1203
+ displayName: "Y",
1204
+ type: "float"
1205
+ },
1206
+ {
1207
+ name: "seed",
1208
+ displayName: "Seed",
1209
+ type: "int"
1210
+ },
1211
+ {
1212
+ name: "octaves",
1213
+ displayName: "Octaves",
1214
+ type: "int"
1215
+ },
1216
+ {
1217
+ name: "frequency",
1218
+ displayName: "Frequency",
1219
+ type: "float"
1220
+ },
1221
+ {
1222
+ name: "persistence",
1223
+ displayName: "Persistence",
1224
+ type: "float"
1225
+ }
1226
+ ],
1227
+ outputs: [
1228
+ {
1229
+ name: "value",
1230
+ displayName: "Value",
1231
+ type: "float"
1232
+ }
1233
+ ],
1234
+ color: "#9c27b0"
1235
+ };
1236
+ var _SampleFBMExecutor = class _SampleFBMExecutor {
1237
+ execute(node, context) {
1238
+ const ctx = context;
1239
+ const x = ctx.evaluateInput(node.id, "x", 0);
1240
+ const y = ctx.evaluateInput(node.id, "y", 0);
1241
+ const seed = ctx.evaluateInput(node.id, "seed", 0);
1242
+ const octaves = ctx.evaluateInput(node.id, "octaves", 6);
1243
+ const frequency = ctx.evaluateInput(node.id, "frequency", 1);
1244
+ const persistence = ctx.evaluateInput(node.id, "persistence", 0.5);
1245
+ const noise = getPerlinNoise(seed);
1246
+ const fbm = new FBM(noise, {
1247
+ octaves,
1248
+ frequency,
1249
+ persistence
1250
+ });
1251
+ const value = fbm.noise2D(x, y);
1252
+ return {
1253
+ outputs: {
1254
+ value
1255
+ }
1256
+ };
1257
+ }
1258
+ };
1259
+ __name(_SampleFBMExecutor, "SampleFBMExecutor");
1260
+ var SampleFBMExecutor = _SampleFBMExecutor;
1261
+ var SeededRandomTemplate = {
1262
+ type: "SeededRandom",
1263
+ title: "Seeded Random",
1264
+ category: "math",
1265
+ description: "Generate deterministic random number / \u751F\u6210\u786E\u5B9A\u6027\u968F\u673A\u6570",
1266
+ keywords: [
1267
+ "random",
1268
+ "seed",
1269
+ "deterministic",
1270
+ "procedural"
1271
+ ],
1272
+ menuPath: [
1273
+ "Procedural",
1274
+ "Random",
1275
+ "Seeded Random"
1276
+ ],
1277
+ isPure: true,
1278
+ inputs: [
1279
+ {
1280
+ name: "seed",
1281
+ displayName: "Seed",
1282
+ type: "int"
1283
+ },
1284
+ {
1285
+ name: "index",
1286
+ displayName: "Index",
1287
+ type: "int"
1288
+ }
1289
+ ],
1290
+ outputs: [
1291
+ {
1292
+ name: "value",
1293
+ displayName: "Value",
1294
+ type: "float"
1295
+ }
1296
+ ],
1297
+ color: "#9c27b0"
1298
+ };
1299
+ var _SeededRandomExecutor = class _SeededRandomExecutor {
1300
+ execute(node, context) {
1301
+ const ctx = context;
1302
+ const seed = ctx.evaluateInput(node.id, "seed", 0);
1303
+ const index = ctx.evaluateInput(node.id, "index", 0);
1304
+ const rng = new SeededRandom(seed + index * 12345);
1305
+ const value = rng.next();
1306
+ return {
1307
+ outputs: {
1308
+ value
1309
+ }
1310
+ };
1311
+ }
1312
+ };
1313
+ __name(_SeededRandomExecutor, "SeededRandomExecutor");
1314
+ var SeededRandomExecutor = _SeededRandomExecutor;
1315
+ var SeededRandomIntTemplate = {
1316
+ type: "SeededRandomInt",
1317
+ title: "Seeded Random Int",
1318
+ category: "math",
1319
+ description: "Generate deterministic random integer / \u751F\u6210\u786E\u5B9A\u6027\u968F\u673A\u6574\u6570",
1320
+ keywords: [
1321
+ "random",
1322
+ "seed",
1323
+ "integer",
1324
+ "deterministic"
1325
+ ],
1326
+ menuPath: [
1327
+ "Procedural",
1328
+ "Random",
1329
+ "Seeded Random Int"
1330
+ ],
1331
+ isPure: true,
1332
+ inputs: [
1333
+ {
1334
+ name: "seed",
1335
+ displayName: "Seed",
1336
+ type: "int"
1337
+ },
1338
+ {
1339
+ name: "index",
1340
+ displayName: "Index",
1341
+ type: "int"
1342
+ },
1343
+ {
1344
+ name: "min",
1345
+ displayName: "Min",
1346
+ type: "int"
1347
+ },
1348
+ {
1349
+ name: "max",
1350
+ displayName: "Max",
1351
+ type: "int"
1352
+ }
1353
+ ],
1354
+ outputs: [
1355
+ {
1356
+ name: "value",
1357
+ displayName: "Value",
1358
+ type: "int"
1359
+ }
1360
+ ],
1361
+ color: "#9c27b0"
1362
+ };
1363
+ var _SeededRandomIntExecutor = class _SeededRandomIntExecutor {
1364
+ execute(node, context) {
1365
+ const ctx = context;
1366
+ const seed = ctx.evaluateInput(node.id, "seed", 0);
1367
+ const index = ctx.evaluateInput(node.id, "index", 0);
1368
+ const min = ctx.evaluateInput(node.id, "min", 0);
1369
+ const max = ctx.evaluateInput(node.id, "max", 100);
1370
+ const rng = new SeededRandom(seed + index * 12345);
1371
+ const value = rng.nextInt(min, max);
1372
+ return {
1373
+ outputs: {
1374
+ value
1375
+ }
1376
+ };
1377
+ }
1378
+ };
1379
+ __name(_SeededRandomIntExecutor, "SeededRandomIntExecutor");
1380
+ var SeededRandomIntExecutor = _SeededRandomIntExecutor;
1381
+ var WeightedPickTemplate = {
1382
+ type: "WeightedPick",
1383
+ title: "Weighted Pick",
1384
+ category: "math",
1385
+ description: "Pick from weighted options / \u4ECE\u52A0\u6743\u9009\u9879\u4E2D\u9009\u62E9",
1386
+ keywords: [
1387
+ "random",
1388
+ "weight",
1389
+ "pick",
1390
+ "select",
1391
+ "loot"
1392
+ ],
1393
+ menuPath: [
1394
+ "Procedural",
1395
+ "Random",
1396
+ "Weighted Pick"
1397
+ ],
1398
+ isPure: true,
1399
+ inputs: [
1400
+ {
1401
+ name: "seed",
1402
+ displayName: "Seed",
1403
+ type: "int"
1404
+ },
1405
+ {
1406
+ name: "index",
1407
+ displayName: "Index",
1408
+ type: "int"
1409
+ },
1410
+ {
1411
+ name: "items",
1412
+ displayName: "Items",
1413
+ type: "array"
1414
+ },
1415
+ {
1416
+ name: "weights",
1417
+ displayName: "Weights",
1418
+ type: "array"
1419
+ }
1420
+ ],
1421
+ outputs: [
1422
+ {
1423
+ name: "value",
1424
+ displayName: "Value",
1425
+ type: "any"
1426
+ },
1427
+ {
1428
+ name: "selectedIndex",
1429
+ displayName: "Index",
1430
+ type: "int"
1431
+ }
1432
+ ],
1433
+ color: "#9c27b0"
1434
+ };
1435
+ var _WeightedPickExecutor = class _WeightedPickExecutor {
1436
+ execute(node, context) {
1437
+ const ctx = context;
1438
+ const seed = ctx.evaluateInput(node.id, "seed", 0);
1439
+ const index = ctx.evaluateInput(node.id, "index", 0);
1440
+ const items = ctx.evaluateInput(node.id, "items", []);
1441
+ const weights = ctx.evaluateInput(node.id, "weights", []);
1442
+ if (items.length === 0) {
1443
+ return {
1444
+ outputs: {
1445
+ value: null,
1446
+ selectedIndex: -1
1447
+ }
1448
+ };
1449
+ }
1450
+ const rng = new SeededRandom(seed + index * 12345);
1451
+ const weightedItems = items.map((item, i) => ({
1452
+ value: {
1453
+ value: item,
1454
+ index: i
1455
+ },
1456
+ weight: weights[i] ?? 1
1457
+ }));
1458
+ const result = weightedPick(weightedItems, rng);
1459
+ return {
1460
+ outputs: {
1461
+ value: result.value,
1462
+ selectedIndex: result.index
1463
+ }
1464
+ };
1465
+ }
1466
+ };
1467
+ __name(_WeightedPickExecutor, "WeightedPickExecutor");
1468
+ var WeightedPickExecutor = _WeightedPickExecutor;
1469
+ var ShuffleArrayTemplate = {
1470
+ type: "ShuffleArray",
1471
+ title: "Shuffle Array",
1472
+ category: "math",
1473
+ description: "Shuffle array with seed / \u4F7F\u7528\u79CD\u5B50\u6D17\u724C\u6570\u7EC4",
1474
+ keywords: [
1475
+ "random",
1476
+ "shuffle",
1477
+ "array",
1478
+ "order"
1479
+ ],
1480
+ menuPath: [
1481
+ "Procedural",
1482
+ "Random",
1483
+ "Shuffle Array"
1484
+ ],
1485
+ isPure: true,
1486
+ inputs: [
1487
+ {
1488
+ name: "seed",
1489
+ displayName: "Seed",
1490
+ type: "int"
1491
+ },
1492
+ {
1493
+ name: "array",
1494
+ displayName: "Array",
1495
+ type: "array"
1496
+ }
1497
+ ],
1498
+ outputs: [
1499
+ {
1500
+ name: "result",
1501
+ displayName: "Result",
1502
+ type: "array"
1503
+ }
1504
+ ],
1505
+ color: "#9c27b0"
1506
+ };
1507
+ var _ShuffleArrayExecutor = class _ShuffleArrayExecutor {
1508
+ execute(node, context) {
1509
+ const ctx = context;
1510
+ const seed = ctx.evaluateInput(node.id, "seed", 0);
1511
+ const array = ctx.evaluateInput(node.id, "array", []);
1512
+ const rng = new SeededRandom(seed);
1513
+ const result = shuffle([
1514
+ ...array
1515
+ ], rng);
1516
+ return {
1517
+ outputs: {
1518
+ result
1519
+ }
1520
+ };
1521
+ }
1522
+ };
1523
+ __name(_ShuffleArrayExecutor, "ShuffleArrayExecutor");
1524
+ var ShuffleArrayExecutor = _ShuffleArrayExecutor;
1525
+ var PickRandomTemplate = {
1526
+ type: "PickRandom",
1527
+ title: "Pick Random",
1528
+ category: "math",
1529
+ description: "Pick random element from array / \u4ECE\u6570\u7EC4\u4E2D\u968F\u673A\u9009\u62E9\u5143\u7D20",
1530
+ keywords: [
1531
+ "random",
1532
+ "pick",
1533
+ "array",
1534
+ "select"
1535
+ ],
1536
+ menuPath: [
1537
+ "Procedural",
1538
+ "Random",
1539
+ "Pick Random"
1540
+ ],
1541
+ isPure: true,
1542
+ inputs: [
1543
+ {
1544
+ name: "seed",
1545
+ displayName: "Seed",
1546
+ type: "int"
1547
+ },
1548
+ {
1549
+ name: "index",
1550
+ displayName: "Index",
1551
+ type: "int"
1552
+ },
1553
+ {
1554
+ name: "array",
1555
+ displayName: "Array",
1556
+ type: "array"
1557
+ }
1558
+ ],
1559
+ outputs: [
1560
+ {
1561
+ name: "value",
1562
+ displayName: "Value",
1563
+ type: "any"
1564
+ }
1565
+ ],
1566
+ color: "#9c27b0"
1567
+ };
1568
+ var _PickRandomExecutor = class _PickRandomExecutor {
1569
+ execute(node, context) {
1570
+ const ctx = context;
1571
+ const seed = ctx.evaluateInput(node.id, "seed", 0);
1572
+ const index = ctx.evaluateInput(node.id, "index", 0);
1573
+ const array = ctx.evaluateInput(node.id, "array", []);
1574
+ if (array.length === 0) {
1575
+ return {
1576
+ outputs: {
1577
+ value: null
1578
+ }
1579
+ };
1580
+ }
1581
+ const rng = new SeededRandom(seed + index * 12345);
1582
+ const value = pickOne(array, rng);
1583
+ return {
1584
+ outputs: {
1585
+ value
1586
+ }
1587
+ };
1588
+ }
1589
+ };
1590
+ __name(_PickRandomExecutor, "PickRandomExecutor");
1591
+ var PickRandomExecutor = _PickRandomExecutor;
1592
+ var SampleArrayTemplate = {
1593
+ type: "SampleArray",
1594
+ title: "Sample Array",
1595
+ category: "math",
1596
+ description: "Sample N unique elements from array / \u4ECE\u6570\u7EC4\u4E2D\u91C7\u6837 N \u4E2A\u4E0D\u91CD\u590D\u5143\u7D20",
1597
+ keywords: [
1598
+ "random",
1599
+ "sample",
1600
+ "array",
1601
+ "unique"
1602
+ ],
1603
+ menuPath: [
1604
+ "Procedural",
1605
+ "Random",
1606
+ "Sample Array"
1607
+ ],
1608
+ isPure: true,
1609
+ inputs: [
1610
+ {
1611
+ name: "seed",
1612
+ displayName: "Seed",
1613
+ type: "int"
1614
+ },
1615
+ {
1616
+ name: "array",
1617
+ displayName: "Array",
1618
+ type: "array"
1619
+ },
1620
+ {
1621
+ name: "count",
1622
+ displayName: "Count",
1623
+ type: "int"
1624
+ }
1625
+ ],
1626
+ outputs: [
1627
+ {
1628
+ name: "result",
1629
+ displayName: "Result",
1630
+ type: "array"
1631
+ }
1632
+ ],
1633
+ color: "#9c27b0"
1634
+ };
1635
+ var _SampleArrayExecutor = class _SampleArrayExecutor {
1636
+ execute(node, context) {
1637
+ const ctx = context;
1638
+ const seed = ctx.evaluateInput(node.id, "seed", 0);
1639
+ const array = ctx.evaluateInput(node.id, "array", []);
1640
+ const count = ctx.evaluateInput(node.id, "count", 1);
1641
+ if (array.length === 0 || count <= 0) {
1642
+ return {
1643
+ outputs: {
1644
+ result: []
1645
+ }
1646
+ };
1647
+ }
1648
+ const rng = new SeededRandom(seed);
1649
+ const actualCount = Math.min(count, array.length);
1650
+ const result = sample(array, actualCount, rng);
1651
+ return {
1652
+ outputs: {
1653
+ result
1654
+ }
1655
+ };
1656
+ }
1657
+ };
1658
+ __name(_SampleArrayExecutor, "SampleArrayExecutor");
1659
+ var SampleArrayExecutor = _SampleArrayExecutor;
1660
+ var RandomPointInCircleTemplate = {
1661
+ type: "RandomPointInCircle",
1662
+ title: "Random Point In Circle",
1663
+ category: "math",
1664
+ description: "Generate random point inside circle / \u5728\u5706\u5185\u751F\u6210\u968F\u673A\u70B9",
1665
+ keywords: [
1666
+ "random",
1667
+ "point",
1668
+ "circle",
1669
+ "position"
1670
+ ],
1671
+ menuPath: [
1672
+ "Procedural",
1673
+ "Random",
1674
+ "Random Point In Circle"
1675
+ ],
1676
+ isPure: true,
1677
+ inputs: [
1678
+ {
1679
+ name: "seed",
1680
+ displayName: "Seed",
1681
+ type: "int"
1682
+ },
1683
+ {
1684
+ name: "index",
1685
+ displayName: "Index",
1686
+ type: "int"
1687
+ },
1688
+ {
1689
+ name: "centerX",
1690
+ displayName: "Center X",
1691
+ type: "float"
1692
+ },
1693
+ {
1694
+ name: "centerY",
1695
+ displayName: "Center Y",
1696
+ type: "float"
1697
+ },
1698
+ {
1699
+ name: "radius",
1700
+ displayName: "Radius",
1701
+ type: "float"
1702
+ }
1703
+ ],
1704
+ outputs: [
1705
+ {
1706
+ name: "x",
1707
+ displayName: "X",
1708
+ type: "float"
1709
+ },
1710
+ {
1711
+ name: "y",
1712
+ displayName: "Y",
1713
+ type: "float"
1714
+ }
1715
+ ],
1716
+ color: "#9c27b0"
1717
+ };
1718
+ var _RandomPointInCircleExecutor = class _RandomPointInCircleExecutor {
1719
+ execute(node, context) {
1720
+ const ctx = context;
1721
+ const seed = ctx.evaluateInput(node.id, "seed", 0);
1722
+ const index = ctx.evaluateInput(node.id, "index", 0);
1723
+ const centerX = ctx.evaluateInput(node.id, "centerX", 0);
1724
+ const centerY = ctx.evaluateInput(node.id, "centerY", 0);
1725
+ const radius = ctx.evaluateInput(node.id, "radius", 1);
1726
+ const rng = new SeededRandom(seed + index * 12345);
1727
+ const point = rng.nextPointInCircle(radius);
1728
+ return {
1729
+ outputs: {
1730
+ x: centerX + point.x,
1731
+ y: centerY + point.y
1732
+ }
1733
+ };
1734
+ }
1735
+ };
1736
+ __name(_RandomPointInCircleExecutor, "RandomPointInCircleExecutor");
1737
+ var RandomPointInCircleExecutor = _RandomPointInCircleExecutor;
1738
+ var ProcGenNodeDefinitions = {
1739
+ templates: [
1740
+ SampleNoise2DTemplate,
1741
+ SampleFBMTemplate,
1742
+ SeededRandomTemplate,
1743
+ SeededRandomIntTemplate,
1744
+ WeightedPickTemplate,
1745
+ ShuffleArrayTemplate,
1746
+ PickRandomTemplate,
1747
+ SampleArrayTemplate,
1748
+ RandomPointInCircleTemplate
1749
+ ],
1750
+ executors: /* @__PURE__ */ new Map([
1751
+ [
1752
+ "SampleNoise2D",
1753
+ new SampleNoise2DExecutor()
1754
+ ],
1755
+ [
1756
+ "SampleFBM",
1757
+ new SampleFBMExecutor()
1758
+ ],
1759
+ [
1760
+ "SeededRandom",
1761
+ new SeededRandomExecutor()
1762
+ ],
1763
+ [
1764
+ "SeededRandomInt",
1765
+ new SeededRandomIntExecutor()
1766
+ ],
1767
+ [
1768
+ "WeightedPick",
1769
+ new WeightedPickExecutor()
1770
+ ],
1771
+ [
1772
+ "ShuffleArray",
1773
+ new ShuffleArrayExecutor()
1774
+ ],
1775
+ [
1776
+ "PickRandom",
1777
+ new PickRandomExecutor()
1778
+ ],
1779
+ [
1780
+ "SampleArray",
1781
+ new SampleArrayExecutor()
1782
+ ],
1783
+ [
1784
+ "RandomPointInCircle",
1785
+ new RandomPointInCircleExecutor()
1786
+ ]
1787
+ ])
1788
+ };
1789
+
1790
+ export { FBM, PerlinNoise, PickRandomExecutor, PickRandomTemplate, ProcGenNodeDefinitions, RandomPointInCircleExecutor, RandomPointInCircleTemplate, SampleArrayExecutor, SampleArrayTemplate, SampleFBMExecutor, SampleFBMTemplate, SampleNoise2DExecutor, SampleNoise2DTemplate, SeededRandom, SeededRandomExecutor, SeededRandomIntExecutor, SeededRandomIntTemplate, SeededRandomTemplate, ShuffleArrayExecutor, ShuffleArrayTemplate, SimplexNoise, WeightedPickExecutor, WeightedPickTemplate, WeightedRandom, WorleyNoise, createFBM, createPerlinNoise, createSeededRandom, createSimplexNoise, createWeightedRandom, createWorleyNoise, pickOne, randomIntegers, sample, sampleWithReplacement, shuffle, shuffleCopy, weightedPick, weightedPickFromMap, weightedSample };
1791
+ //# sourceMappingURL=index.js.map
1792
+ //# sourceMappingURL=index.js.map