@holoscript/std 3.1.1 → 6.0.3

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.
Files changed (106) hide show
  1. package/CHANGELOG.md +7 -0
  2. package/LICENSE +21 -0
  3. package/dist/__tests__/EconomicPrimitives.test.d.ts +2 -0
  4. package/dist/__tests__/EconomicTraits.test.d.ts +2 -0
  5. package/dist/__tests__/SimulationLabPrimitives.test.d.ts +2 -0
  6. package/dist/__tests__/collections.test.d.ts +2 -0
  7. package/dist/__tests__/events.test.d.ts +2 -0
  8. package/dist/__tests__/index.test.d.ts +2 -0
  9. package/dist/__tests__/index.test.d.ts.map +1 -0
  10. package/dist/__tests__/materials.test.d.ts +2 -0
  11. package/dist/__tests__/math.test.d.ts +2 -0
  12. package/dist/__tests__/physics.test.d.ts +2 -0
  13. package/dist/__tests__/spatial.test.d.ts +2 -0
  14. package/dist/__tests__/standard-library-fundamentals.test.d.ts +2 -0
  15. package/dist/__tests__/standard-library-fundamentals.test.d.ts.map +1 -0
  16. package/dist/__tests__/string-and-time-utilities.test.d.ts +2 -0
  17. package/dist/__tests__/string-and-time-utilities.test.d.ts.map +1 -0
  18. package/dist/__tests__/string-decoupled.test.d.ts +2 -0
  19. package/dist/__tests__/string.test.d.ts +2 -0
  20. package/dist/__tests__/time.test.d.ts +2 -0
  21. package/dist/chunk-7HVUYGPS.js +679 -0
  22. package/dist/chunk-7HVUYGPS.js.map +1 -0
  23. package/dist/chunk-P4O3WNG2.js +287 -0
  24. package/dist/chunk-P4O3WNG2.js.map +1 -0
  25. package/dist/chunk-PFX2JM4X.js +683 -0
  26. package/dist/chunk-PFX2JM4X.js.map +1 -0
  27. package/dist/chunk-W2Q3LUCM.js +348 -0
  28. package/dist/chunk-W2Q3LUCM.js.map +1 -0
  29. package/dist/chunk-WS6W35YC.js +443 -0
  30. package/dist/chunk-WS6W35YC.js.map +1 -0
  31. package/dist/chunk-ZXVZAQCZ.js +470 -0
  32. package/dist/chunk-ZXVZAQCZ.js.map +1 -0
  33. package/dist/collections.cjs +715 -0
  34. package/dist/collections.cjs.map +1 -0
  35. package/dist/collections.d.ts +177 -0
  36. package/dist/collections.js +17 -0
  37. package/dist/collections.js.map +1 -0
  38. package/dist/events.d.ts +32 -0
  39. package/dist/index.cjs +4101 -0
  40. package/dist/index.cjs.map +1 -0
  41. package/dist/index.d.ts +101 -0
  42. package/dist/index.js +1270 -190
  43. package/dist/index.js.map +1 -0
  44. package/dist/materials.d.ts +50 -0
  45. package/dist/math.cjs +591 -0
  46. package/dist/math.cjs.map +1 -0
  47. package/dist/math.d.ts +162 -0
  48. package/dist/math.js +53 -0
  49. package/dist/math.js.map +1 -0
  50. package/dist/physics.d.ts +59 -0
  51. package/dist/spatial.d.ts +82 -0
  52. package/dist/string.basic.test.d.ts +5 -0
  53. package/dist/string.basic.test.d.ts.map +1 -0
  54. package/dist/string.cjs +422 -0
  55. package/dist/string.cjs.map +1 -0
  56. package/dist/string.d.ts +212 -0
  57. package/dist/string.d.ts.map +1 -1
  58. package/dist/string.js +107 -0
  59. package/dist/string.js.map +1 -0
  60. package/dist/string.test.d.ts +5 -0
  61. package/dist/string.test.d.ts.map +1 -0
  62. package/dist/time.cjs +512 -0
  63. package/dist/time.cjs.map +1 -0
  64. package/dist/time.d.ts +215 -0
  65. package/dist/time.js +43 -0
  66. package/dist/time.js.map +1 -0
  67. package/dist/traits/ARTraits.d.ts +14 -0
  68. package/dist/traits/EconomicPrimitives.cjs +335 -0
  69. package/dist/traits/EconomicPrimitives.cjs.map +1 -0
  70. package/dist/traits/EconomicPrimitives.d.ts +345 -0
  71. package/dist/traits/EconomicPrimitives.js +55 -0
  72. package/dist/traits/EconomicPrimitives.js.map +1 -0
  73. package/dist/traits/EconomicTraits.cjs +471 -0
  74. package/dist/traits/EconomicTraits.cjs.map +1 -0
  75. package/dist/traits/EconomicTraits.d.ts +71 -0
  76. package/dist/traits/EconomicTraits.js +17 -0
  77. package/dist/traits/EconomicTraits.js.map +1 -0
  78. package/dist/traits/IoTTraits.d.ts +14 -0
  79. package/dist/traits/SimulationLabPrimitives.d.ts +187 -0
  80. package/dist/traits/SimulationLabTraits.d.ts +42 -0
  81. package/dist/traits/VRRTraits.d.ts +150 -0
  82. package/dist/traits/__tests__/ARTraits.test.d.ts +2 -0
  83. package/dist/traits/__tests__/ARTraits.test.d.ts.map +1 -0
  84. package/dist/traits/__tests__/EconomicPrimitives.test.d.ts +2 -0
  85. package/dist/traits/__tests__/EconomicPrimitives.test.d.ts.map +1 -0
  86. package/dist/traits/__tests__/EconomicTraits.test.d.ts +2 -0
  87. package/dist/traits/__tests__/EconomicTraits.test.d.ts.map +1 -0
  88. package/dist/types.d.ts +202 -0
  89. package/error-utf8.log +6 -0
  90. package/error.log +0 -0
  91. package/package.json +30 -18
  92. package/src/__tests__/index.test.ts +14 -0
  93. package/src/__tests__/{Sprint33.test.ts → standard-library-fundamentals.test.ts} +70 -70
  94. package/src/__tests__/{Sprint56.test.ts → string-and-time-utilities.test.ts} +64 -64
  95. package/src/__tests__/string-decoupled.test.ts +0 -2
  96. package/src/string.basic.test.ts +1 -1
  97. package/src/string.test.ts +4 -4
  98. package/src/string.ts +30 -15
  99. package/src/time.ts +1 -1
  100. package/src/traits/__tests__/ARTraits.test.ts +14 -0
  101. package/src/traits/__tests__/EconomicPrimitives.test.ts +14 -0
  102. package/src/traits/__tests__/EconomicTraits.test.ts +14 -0
  103. package/std_error.log +5 -0
  104. package/tsup.config.ts +17 -0
  105. package/dist/__tests__/Sprint33.test.d.ts.map +0 -1
  106. package/dist/__tests__/Sprint56.test.d.ts.map +0 -1
package/dist/index.cjs ADDED
@@ -0,0 +1,4101 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod2) => __copyProps(__defProp({}, "__esModule", { value: true }), mod2);
19
+
20
+ // src/index.ts
21
+ var index_exports = {};
22
+ __export(index_exports, {
23
+ AABB: () => AABB,
24
+ CountdownTimer: () => CountdownTimer,
25
+ DEFAULT_BONDING_CURVE: () => DEFAULT_BONDING_CURVE,
26
+ DEFAULT_DEPRECIATION: () => DEFAULT_DEPRECIATION,
27
+ DEFAULT_PID: () => DEFAULT_PID,
28
+ DEFAULT_WEALTH_TAX: () => DEFAULT_WEALTH_TAX,
29
+ DEG_TO_RAD: () => DEG_TO_RAD,
30
+ DateTime: () => DateTime,
31
+ EPSILON: () => EPSILON,
32
+ EconomicTraits: () => EconomicTraits,
33
+ EventBus: () => EventBus,
34
+ FrameTimer: () => FrameTimer,
35
+ HALF_PI: () => HALF_PI,
36
+ HoloMap: () => HoloMap,
37
+ HoloSet: () => HoloSet,
38
+ IntervalTimer: () => IntervalTimer,
39
+ List: () => List,
40
+ MATERIAL_PRESETS: () => MATERIAL_PRESETS,
41
+ Map: () => HoloMap,
42
+ PI: () => PI,
43
+ PriorityQueue: () => PriorityQueue,
44
+ Quaternion: () => Quaternion,
45
+ RAD_TO_DEG: () => RAD_TO_DEG,
46
+ Ray: () => Ray,
47
+ Set: () => HoloSet,
48
+ SimulationLabTraits: () => SimulationLabTraits,
49
+ SpatialGrid: () => SpatialGrid,
50
+ Stopwatch: () => Stopwatch,
51
+ TAU: () => TAU,
52
+ Transform: () => Transform,
53
+ Vec3: () => Vec3,
54
+ aabb: () => aabb,
55
+ aabbMath: () => aabbMath,
56
+ arrayToQuat: () => arrayToQuat,
57
+ arrayToVec3: () => arrayToVec3,
58
+ assert: () => assert,
59
+ assertDefined: () => assertDefined,
60
+ bondingCurveBuyCost: () => bondingCurveBuyCost,
61
+ bondingCurvePrice: () => bondingCurvePrice,
62
+ bondingCurveSellRefund: () => bondingCurveSellRefund,
63
+ calculateDepreciation: () => calculateDepreciation,
64
+ calculateRedistribution: () => calculateRedistribution,
65
+ calculateRepairCost: () => calculateRepairCost,
66
+ calculateTaxAmount: () => calculateTaxAmount,
67
+ calculateTaxRate: () => calculateTaxRate,
68
+ camelCase: () => camelCase,
69
+ capitalize: () => capitalize,
70
+ center: () => center,
71
+ chars: () => chars,
72
+ chiSquaredTest: () => chiSquaredTest,
73
+ clamp: () => clamp2,
74
+ clone: () => clone,
75
+ cohensD: () => cohensD,
76
+ collapseWhitespace: () => collapseWhitespace,
77
+ colorToHex: () => colorToHex,
78
+ compose: () => compose,
79
+ constant: () => constant,
80
+ constantCase: () => constantCase,
81
+ containsIgnoreCase: () => containsIgnoreCase,
82
+ count: () => count,
83
+ createBoxCollider: () => createBoxCollider,
84
+ createCapsuleCollider: () => createCapsuleCollider,
85
+ createDualLoopPIDState: () => createDualLoopPIDState,
86
+ createFaucetSinkMetrics: () => createFaucetSinkMetrics,
87
+ createPBRMaterial: () => createPBRMaterial,
88
+ createPIDState: () => createPIDState,
89
+ createRigidbody: () => createRigidbody,
90
+ createSphereCollider: () => createSphereCollider,
91
+ createTicker: () => createTicker,
92
+ debounce: () => debounce,
93
+ dedent: () => dedent,
94
+ degToRad: () => degToRad2,
95
+ depreciatedValue: () => depreciatedValue,
96
+ distance: () => distance,
97
+ endsWithIgnoreCase: () => endsWithIgnoreCase,
98
+ equals: () => equals,
99
+ escapeHtml: () => escapeHtml,
100
+ escapeRegex: () => escapeRegex,
101
+ executeTrade: () => executeTrade,
102
+ expandSweep: () => expandSweep,
103
+ extractMetric: () => extractMetric,
104
+ extractTraits: () => extractTraits,
105
+ format: () => format,
106
+ formatBytes: () => formatBytes,
107
+ formatDuration: () => formatDuration,
108
+ formatNumber: () => formatNumber,
109
+ fract: () => fract,
110
+ generateSweepCombinations: () => generateSweepCombinations,
111
+ generateTxHash: () => generateTxHash,
112
+ getEconomicTrait: () => getEconomicTrait,
113
+ getEconomicTraitNames: () => getEconomicTraitNames,
114
+ getRequiredPermissions: () => getRequiredPermissions,
115
+ getSimulationTrait: () => getSimulationTrait,
116
+ getSimulationTraitNames: () => getSimulationTraitNames,
117
+ groupByParameter: () => groupByParameter,
118
+ hrTime: () => hrTime,
119
+ hsl: () => hsl,
120
+ identity: () => identity,
121
+ indent: () => indent,
122
+ inverseLerp: () => inverseLerp,
123
+ isAlpha: () => isAlpha,
124
+ isAlphanumeric: () => isAlphanumeric,
125
+ isBlank: () => isBlank,
126
+ isDestroyed: () => isDestroyed,
127
+ isNotBlank: () => isNotBlank,
128
+ isNumeric: () => isNumeric,
129
+ isParameterRange: () => isParameterRange,
130
+ isValidIdentifier: () => isValidIdentifier,
131
+ join: () => join,
132
+ kebabCase: () => kebabCase,
133
+ lerp: () => lerp2,
134
+ levenshtein: () => levenshtein,
135
+ lines: () => lines,
136
+ mannWhitneyU: () => mannWhitneyU,
137
+ mean: () => mean,
138
+ measure: () => measure,
139
+ mod: () => mod,
140
+ noise: () => noise,
141
+ noop: () => noop,
142
+ now: () => now,
143
+ numberWithCommas: () => numberWithCommas,
144
+ oneSampleTTest: () => oneSampleTTest,
145
+ padLeft: () => padLeft,
146
+ padRight: () => padRight,
147
+ parseColor: () => parseColor,
148
+ pascalCase: () => pascalCase,
149
+ pipe: () => pipe,
150
+ print: () => print,
151
+ printError: () => printError,
152
+ printWarn: () => printWarn,
153
+ quat: () => quat,
154
+ quatMath: () => quatMath,
155
+ quatToArray: () => quatToArray,
156
+ radToDeg: () => radToDeg2,
157
+ random: () => random,
158
+ randomString: () => randomString,
159
+ ray: () => ray,
160
+ recordFaucet: () => recordFaucet,
161
+ recordSink: () => recordSink,
162
+ remap: () => remap,
163
+ removePrefix: () => removePrefix,
164
+ removeSuffix: () => removeSuffix,
165
+ removeWhitespace: () => removeWhitespace,
166
+ repeat: () => repeat,
167
+ resetMetricsPeriod: () => resetMetricsPeriod,
168
+ retry: () => retry,
169
+ reverse: () => reverse,
170
+ rgb: () => rgb,
171
+ rgba: () => rgba,
172
+ schedule: () => schedule,
173
+ scheduleFrame: () => scheduleFrame,
174
+ scheduleInterval: () => scheduleInterval,
175
+ sign: () => sign,
176
+ similarity: () => similarity,
177
+ sleep: () => sleep,
178
+ slugify: () => slugify,
179
+ smootherstep: () => smootherstep,
180
+ smoothstep: () => smoothstep,
181
+ snakeCase: () => snakeCase,
182
+ spatialClamp: () => clamp,
183
+ spatialDegToRad: () => degToRad,
184
+ spatialLerp: () => lerp,
185
+ spatialPrice: () => spatialPrice,
186
+ spatialRadToDeg: () => radToDeg,
187
+ standardDeviation: () => standardDeviation,
188
+ standardError: () => standardError,
189
+ startsWithIgnoreCase: () => startsWithIgnoreCase,
190
+ step: () => step,
191
+ summarizeMetrics: () => summarizeMetrics,
192
+ tTest: () => tTest,
193
+ throttle: () => throttle,
194
+ timed: () => timed,
195
+ titleCase: () => titleCase,
196
+ toDegrees: () => radToDeg2,
197
+ toRadians: () => degToRad2,
198
+ todo: () => todo,
199
+ transform: () => transform,
200
+ truncate: () => truncate,
201
+ truncateMiddle: () => truncateMiddle,
202
+ unescapeHtml: () => unescapeHtml,
203
+ unreachable: () => unreachable,
204
+ unwrap: () => unwrap,
205
+ updateDualLoopPID: () => updateDualLoopPID,
206
+ updatePID: () => updatePID,
207
+ uuid: () => uuid,
208
+ validateTraitComposition: () => validateTraitComposition,
209
+ variance: () => variance,
210
+ vec2: () => vec2,
211
+ vec2Math: () => vec2Math,
212
+ vec3: () => vec3,
213
+ vec3Math: () => vec3Math,
214
+ vec3ToArray: () => vec3ToArray,
215
+ vec4: () => vec4,
216
+ waitUntil: () => waitUntil,
217
+ withTimeout: () => withTimeout,
218
+ wordWrap: () => wordWrap,
219
+ words: () => words,
220
+ wrapString: () => wrap
221
+ });
222
+ module.exports = __toCommonJS(index_exports);
223
+
224
+ // src/types.ts
225
+ function vec2(x = 0, y = 0) {
226
+ return { x, y };
227
+ }
228
+ function vec3(x = 0, y = 0, z = 0) {
229
+ return { x, y, z };
230
+ }
231
+ function vec4(x = 0, y = 0, z = 0, w = 0) {
232
+ return { x, y, z, w };
233
+ }
234
+ function quat(x = 0, y = 0, z = 0, w = 1) {
235
+ return { x, y, z, w };
236
+ }
237
+ function transform(position = vec3(), rotation = quat(), scale = vec3(1, 1, 1)) {
238
+ return { position, rotation, scale };
239
+ }
240
+ function rgb(r, g, b) {
241
+ return { r, g, b };
242
+ }
243
+ function rgba(r, g, b, a = 1) {
244
+ return { r, g, b, a };
245
+ }
246
+ function hsl(h, s, l) {
247
+ return { h, s, l };
248
+ }
249
+ function aabb(min = vec3(), max = vec3()) {
250
+ return { min, max };
251
+ }
252
+ function ray(origin, direction) {
253
+ return { origin, direction };
254
+ }
255
+ function vec3ToArray(v) {
256
+ return [v.x, v.y, v.z];
257
+ }
258
+ function arrayToVec3(arr) {
259
+ return { x: arr[0] || 0, y: arr[1] || 0, z: arr[2] || 0 };
260
+ }
261
+ function quatToArray(q) {
262
+ return [q.x, q.y, q.z, q.w];
263
+ }
264
+ function arrayToQuat(arr) {
265
+ return { x: arr[0] || 0, y: arr[1] || 0, z: arr[2] || 0, w: arr[3] ?? 1 };
266
+ }
267
+ function parseColor(color) {
268
+ if (typeof color === "string") {
269
+ if (color.startsWith("#")) {
270
+ const hex = color.slice(1);
271
+ if (hex.length === 3) {
272
+ return {
273
+ r: parseInt(hex[0] + hex[0], 16) / 255,
274
+ g: parseInt(hex[1] + hex[1], 16) / 255,
275
+ b: parseInt(hex[2] + hex[2], 16) / 255,
276
+ a: 1
277
+ };
278
+ } else if (hex.length === 6) {
279
+ return {
280
+ r: parseInt(hex.slice(0, 2), 16) / 255,
281
+ g: parseInt(hex.slice(2, 4), 16) / 255,
282
+ b: parseInt(hex.slice(4, 6), 16) / 255,
283
+ a: 1
284
+ };
285
+ } else if (hex.length === 8) {
286
+ return {
287
+ r: parseInt(hex.slice(0, 2), 16) / 255,
288
+ g: parseInt(hex.slice(2, 4), 16) / 255,
289
+ b: parseInt(hex.slice(4, 6), 16) / 255,
290
+ a: parseInt(hex.slice(6, 8), 16) / 255
291
+ };
292
+ }
293
+ }
294
+ const namedColors = {
295
+ white: { r: 1, g: 1, b: 1, a: 1 },
296
+ black: { r: 0, g: 0, b: 0, a: 1 },
297
+ red: { r: 1, g: 0, b: 0, a: 1 },
298
+ green: { r: 0, g: 1, b: 0, a: 1 },
299
+ blue: { r: 0, g: 0, b: 1, a: 1 },
300
+ yellow: { r: 1, g: 1, b: 0, a: 1 },
301
+ cyan: { r: 0, g: 1, b: 1, a: 1 },
302
+ magenta: { r: 1, g: 0, b: 1, a: 1 }
303
+ };
304
+ return namedColors[color.toLowerCase()] || { r: 1, g: 1, b: 1, a: 1 };
305
+ }
306
+ if (typeof color === "number") {
307
+ return {
308
+ r: (color >> 16 & 255) / 255,
309
+ g: (color >> 8 & 255) / 255,
310
+ b: (color & 255) / 255,
311
+ a: 1
312
+ };
313
+ }
314
+ if ("h" in color) {
315
+ const { h, s, l } = color;
316
+ const c = (1 - Math.abs(2 * l - 1)) * s;
317
+ const x = c * (1 - Math.abs(h / 60 % 2 - 1));
318
+ const m = l - c / 2;
319
+ let r = 0, g = 0, b = 0;
320
+ if (h < 60) {
321
+ r = c;
322
+ g = x;
323
+ } else if (h < 120) {
324
+ r = x;
325
+ g = c;
326
+ } else if (h < 180) {
327
+ g = c;
328
+ b = x;
329
+ } else if (h < 240) {
330
+ g = x;
331
+ b = c;
332
+ } else if (h < 300) {
333
+ r = x;
334
+ b = c;
335
+ } else {
336
+ r = c;
337
+ b = x;
338
+ }
339
+ return { r: r + m, g: g + m, b: b + m, a: 1 };
340
+ }
341
+ if ("a" in color) {
342
+ return color;
343
+ }
344
+ return { ...color, a: 1 };
345
+ }
346
+ function colorToHex(color) {
347
+ const r = Math.round(color.r * 255).toString(16).padStart(2, "0");
348
+ const g = Math.round(color.g * 255).toString(16).padStart(2, "0");
349
+ const b = Math.round(color.b * 255).toString(16).padStart(2, "0");
350
+ return `#${r}${g}${b}`;
351
+ }
352
+
353
+ // src/spatial.ts
354
+ var Vec3 = class _Vec3 {
355
+ constructor(x = 0, y = 0, z = 0) {
356
+ this.x = x;
357
+ this.y = y;
358
+ this.z = z;
359
+ }
360
+ static zero() {
361
+ return new _Vec3(0, 0, 0);
362
+ }
363
+ static one() {
364
+ return new _Vec3(1, 1, 1);
365
+ }
366
+ static up() {
367
+ return new _Vec3(0, 1, 0);
368
+ }
369
+ static down() {
370
+ return new _Vec3(0, -1, 0);
371
+ }
372
+ static forward() {
373
+ return new _Vec3(0, 0, -1);
374
+ }
375
+ static right() {
376
+ return new _Vec3(1, 0, 0);
377
+ }
378
+ add(other) {
379
+ return new _Vec3(this.x + other.x, this.y + other.y, this.z + other.z);
380
+ }
381
+ sub(other) {
382
+ return new _Vec3(this.x - other.x, this.y - other.y, this.z - other.z);
383
+ }
384
+ mul(s) {
385
+ return new _Vec3(this.x * s, this.y * s, this.z * s);
386
+ }
387
+ div(s) {
388
+ return new _Vec3(this.x / s, this.y / s, this.z / s);
389
+ }
390
+ dot(other) {
391
+ return this.x * other.x + this.y * other.y + this.z * other.z;
392
+ }
393
+ cross(other) {
394
+ return new _Vec3(
395
+ this.y * other.z - this.z * other.y,
396
+ this.z * other.x - this.x * other.z,
397
+ this.x * other.y - this.y * other.x
398
+ );
399
+ }
400
+ length() {
401
+ return Math.sqrt(this.x * this.x + this.y * this.y + this.z * this.z);
402
+ }
403
+ lengthSquared() {
404
+ return this.x * this.x + this.y * this.y + this.z * this.z;
405
+ }
406
+ normalize() {
407
+ const l = this.length();
408
+ return l > 0 ? this.div(l) : _Vec3.zero();
409
+ }
410
+ distanceTo(other) {
411
+ return this.sub(other).length();
412
+ }
413
+ lerp(other, t) {
414
+ return this.add(other.sub(this).mul(t));
415
+ }
416
+ toArray() {
417
+ return [this.x, this.y, this.z];
418
+ }
419
+ static fromArray(arr) {
420
+ return new _Vec3(arr[0] || 0, arr[1] || 0, arr[2] || 0);
421
+ }
422
+ equals(other, epsilon = 1e-6) {
423
+ return Math.abs(this.x - other.x) < epsilon && Math.abs(this.y - other.y) < epsilon && Math.abs(this.z - other.z) < epsilon;
424
+ }
425
+ toString() {
426
+ return `Vec3(${this.x}, ${this.y}, ${this.z})`;
427
+ }
428
+ };
429
+ var Quaternion = class _Quaternion {
430
+ constructor(x = 0, y = 0, z = 0, w = 1) {
431
+ this.x = x;
432
+ this.y = y;
433
+ this.z = z;
434
+ this.w = w;
435
+ }
436
+ static identity() {
437
+ return new _Quaternion(0, 0, 0, 1);
438
+ }
439
+ static fromEuler(x, y, z) {
440
+ const cx = Math.cos(x * 0.5), sx = Math.sin(x * 0.5);
441
+ const cy = Math.cos(y * 0.5), sy = Math.sin(y * 0.5);
442
+ const cz = Math.cos(z * 0.5), sz = Math.sin(z * 0.5);
443
+ return new _Quaternion(
444
+ sx * cy * cz - cx * sy * sz,
445
+ cx * sy * cz + sx * cy * sz,
446
+ cx * cy * sz - sx * sy * cz,
447
+ cx * cy * cz + sx * sy * sz
448
+ );
449
+ }
450
+ static fromAxisAngle(axis, angle) {
451
+ const half = angle * 0.5;
452
+ const s = Math.sin(half);
453
+ const n = axis.normalize();
454
+ return new _Quaternion(n.x * s, n.y * s, n.z * s, Math.cos(half));
455
+ }
456
+ multiply(other) {
457
+ return new _Quaternion(
458
+ this.w * other.x + this.x * other.w + this.y * other.z - this.z * other.y,
459
+ this.w * other.y - this.x * other.z + this.y * other.w + this.z * other.x,
460
+ this.w * other.z + this.x * other.y - this.y * other.x + this.z * other.w,
461
+ this.w * other.w - this.x * other.x - this.y * other.y - this.z * other.z
462
+ );
463
+ }
464
+ rotateVec3(v) {
465
+ const u = new Vec3(this.x, this.y, this.z);
466
+ const s = this.w;
467
+ return u.mul(2 * u.dot(v)).add(v.mul(s * s - u.dot(u))).add(u.cross(v).mul(2 * s));
468
+ }
469
+ slerp(other, t) {
470
+ let dot = this.x * other.x + this.y * other.y + this.z * other.z + this.w * other.w;
471
+ const neg = dot < 0;
472
+ if (neg) dot = -dot;
473
+ if (dot > 0.9995) {
474
+ const r = new _Quaternion(
475
+ this.x + t * ((neg ? -other.x : other.x) - this.x),
476
+ this.y + t * ((neg ? -other.y : other.y) - this.y),
477
+ this.z + t * ((neg ? -other.z : other.z) - this.z),
478
+ this.w + t * ((neg ? -other.w : other.w) - this.w)
479
+ );
480
+ const len = Math.sqrt(r.x * r.x + r.y * r.y + r.z * r.z + r.w * r.w);
481
+ return new _Quaternion(r.x / len, r.y / len, r.z / len, r.w / len);
482
+ }
483
+ const theta = Math.acos(dot);
484
+ const sinTheta = Math.sin(theta);
485
+ const a = Math.sin((1 - t) * theta) / sinTheta;
486
+ const b = Math.sin(t * theta) / sinTheta * (neg ? -1 : 1);
487
+ return new _Quaternion(
488
+ a * this.x + b * other.x,
489
+ a * this.y + b * other.y,
490
+ a * this.z + b * other.z,
491
+ a * this.w + b * other.w
492
+ );
493
+ }
494
+ normalize() {
495
+ const len = Math.sqrt(this.x * this.x + this.y * this.y + this.z * this.z + this.w * this.w);
496
+ return new _Quaternion(this.x / len, this.y / len, this.z / len, this.w / len);
497
+ }
498
+ toEuler() {
499
+ const sinr = 2 * (this.w * this.x + this.y * this.z);
500
+ const cosr = 1 - 2 * (this.x * this.x + this.y * this.y);
501
+ const sinp = 2 * (this.w * this.y - this.z * this.x);
502
+ const siny = 2 * (this.w * this.z + this.x * this.y);
503
+ const cosy = 1 - 2 * (this.y * this.y + this.z * this.z);
504
+ return new Vec3(
505
+ Math.atan2(sinr, cosr),
506
+ Math.abs(sinp) >= 1 ? Math.sign(sinp) * Math.PI / 2 : Math.asin(sinp),
507
+ Math.atan2(siny, cosy)
508
+ );
509
+ }
510
+ };
511
+ var Transform = class _Transform {
512
+ constructor(position = Vec3.zero(), rotation = Quaternion.identity(), scale = Vec3.one()) {
513
+ this.position = position;
514
+ this.rotation = rotation;
515
+ this.scale = scale;
516
+ }
517
+ static identity() {
518
+ return new _Transform();
519
+ }
520
+ transformPoint(point) {
521
+ const scaled = new Vec3(point.x * this.scale.x, point.y * this.scale.y, point.z * this.scale.z);
522
+ return this.rotation.rotateVec3(scaled).add(this.position);
523
+ }
524
+ transformDirection(dir) {
525
+ return this.rotation.rotateVec3(dir);
526
+ }
527
+ };
528
+ var Ray = class {
529
+ constructor(origin, direction) {
530
+ this.origin = origin;
531
+ this.direction = direction;
532
+ }
533
+ pointAt(t) {
534
+ return this.origin.add(this.direction.mul(t));
535
+ }
536
+ };
537
+ var AABB = class {
538
+ constructor(min, max) {
539
+ this.min = min;
540
+ this.max = max;
541
+ }
542
+ contains(point) {
543
+ return point.x >= this.min.x && point.x <= this.max.x && point.y >= this.min.y && point.y <= this.max.y && point.z >= this.min.z && point.z <= this.max.z;
544
+ }
545
+ intersects(other) {
546
+ return this.min.x <= other.max.x && this.max.x >= other.min.x && this.min.y <= other.max.y && this.max.y >= other.min.y && this.min.z <= other.max.z && this.max.z >= other.min.z;
547
+ }
548
+ center() {
549
+ return this.min.add(this.max).div(2);
550
+ }
551
+ size() {
552
+ return this.max.sub(this.min);
553
+ }
554
+ intersectsRay(ray2) {
555
+ let tmin = (this.min.x - ray2.origin.x) / ray2.direction.x;
556
+ let tmax = (this.max.x - ray2.origin.x) / ray2.direction.x;
557
+ if (tmin > tmax) [tmin, tmax] = [tmax, tmin];
558
+ let tymin = (this.min.y - ray2.origin.y) / ray2.direction.y;
559
+ let tymax = (this.max.y - ray2.origin.y) / ray2.direction.y;
560
+ if (tymin > tymax) [tymin, tymax] = [tymax, tymin];
561
+ if (tmin > tymax || tymin > tmax) return null;
562
+ tmin = Math.max(tmin, tymin);
563
+ tmax = Math.min(tmax, tymax);
564
+ let tzmin = (this.min.z - ray2.origin.z) / ray2.direction.z;
565
+ let tzmax = (this.max.z - ray2.origin.z) / ray2.direction.z;
566
+ if (tzmin > tzmax) [tzmin, tzmax] = [tzmax, tzmin];
567
+ if (tmin > tzmax || tzmin > tmax) return null;
568
+ return Math.max(tmin, tzmin);
569
+ }
570
+ };
571
+ function distance(a, b) {
572
+ return a.distanceTo(b);
573
+ }
574
+ function lerp(a, b, t) {
575
+ return a + (b - a) * t;
576
+ }
577
+ function clamp(v, min, max) {
578
+ return Math.min(Math.max(v, min), max);
579
+ }
580
+ function degToRad(deg) {
581
+ return deg * (Math.PI / 180);
582
+ }
583
+ function radToDeg(rad) {
584
+ return rad * (180 / Math.PI);
585
+ }
586
+
587
+ // src/physics.ts
588
+ function createBoxCollider(halfExtents, options) {
589
+ return {
590
+ shape: "box",
591
+ isTrigger: false,
592
+ friction: 0.5,
593
+ restitution: 0,
594
+ halfExtents,
595
+ ...options
596
+ };
597
+ }
598
+ function createSphereCollider(radius, options) {
599
+ return { shape: "sphere", isTrigger: false, friction: 0.5, restitution: 0, radius, ...options };
600
+ }
601
+ function createCapsuleCollider(radius, height, options) {
602
+ return {
603
+ shape: "capsule",
604
+ isTrigger: false,
605
+ friction: 0.5,
606
+ restitution: 0,
607
+ radius,
608
+ height,
609
+ ...options
610
+ };
611
+ }
612
+ function createRigidbody(mass, options) {
613
+ return {
614
+ mass,
615
+ useGravity: true,
616
+ linearDamping: 0,
617
+ angularDamping: 0.05,
618
+ freezePosition: [false, false, false],
619
+ freezeRotation: [false, false, false],
620
+ isKinematic: false,
621
+ ...options
622
+ };
623
+ }
624
+
625
+ // src/materials.ts
626
+ var MATERIAL_PRESETS = {
627
+ metal: { roughness: 0.2, metallic: 1 },
628
+ wood: { roughness: 0.85, metallic: 0, baseColor: "#8B6914" },
629
+ glass: { roughness: 0.05, metallic: 0, opacity: 0.3, ior: 1.5 },
630
+ plastic: { roughness: 0.4, metallic: 0 },
631
+ concrete: { roughness: 0.95, metallic: 0, baseColor: "#808080" },
632
+ fabric: { roughness: 0.9, metallic: 0, subsurface: 0.2 },
633
+ water: { roughness: 0.05, metallic: 0, opacity: 0.7, ior: 1.33 },
634
+ rubber: { roughness: 0.95, metallic: 0, baseColor: "#222222" },
635
+ marble: { roughness: 0.3, metallic: 0, baseColor: "#f0f0f0" },
636
+ skin: { roughness: 0.6, metallic: 0, subsurface: 0.5 },
637
+ foliage: { roughness: 0.8, metallic: 0, baseColor: "#2d5a27", subsurface: 0.3 },
638
+ chrome: { roughness: 0.05, metallic: 1, baseColor: "#cccccc" },
639
+ gold: { roughness: 0.2, metallic: 1, baseColor: "#ffd700" },
640
+ copper: { roughness: 0.3, metallic: 1, baseColor: "#b87333" },
641
+ ice: { roughness: 0.1, metallic: 0, opacity: 0.8, ior: 1.31 }
642
+ };
643
+ function createPBRMaterial(name, preset, overrides) {
644
+ const base = preset ? MATERIAL_PRESETS[preset] : {};
645
+ return {
646
+ name,
647
+ baseColor: "#ffffff",
648
+ roughness: 0.5,
649
+ metallic: 0,
650
+ ...base,
651
+ ...overrides
652
+ };
653
+ }
654
+
655
+ // src/events.ts
656
+ var EventBus = class {
657
+ listeners = /* @__PURE__ */ new Map();
658
+ wildcardListeners = [];
659
+ /** Register an event listener. */
660
+ on(event, handler) {
661
+ if (!this.listeners.has(event)) this.listeners.set(event, []);
662
+ const listener = { handler, once: false };
663
+ this.listeners.get(event).push(listener);
664
+ return () => this.off(event, handler);
665
+ }
666
+ /** Register a one-time event listener. */
667
+ once(event, handler) {
668
+ if (!this.listeners.has(event)) this.listeners.set(event, []);
669
+ const listener = { handler, once: true };
670
+ this.listeners.get(event).push(listener);
671
+ return () => this.off(event, handler);
672
+ }
673
+ /** Remove an event listener. */
674
+ off(event, handler) {
675
+ const list = this.listeners.get(event);
676
+ if (!list) return;
677
+ this.listeners.set(
678
+ event,
679
+ list.filter((l) => l.handler !== handler)
680
+ );
681
+ }
682
+ /** Emit an event to all registered listeners. */
683
+ emit(event, data) {
684
+ const list = this.listeners.get(event);
685
+ if (list) {
686
+ const remaining = [];
687
+ for (const l of list) {
688
+ l.handler(data);
689
+ if (!l.once) remaining.push(l);
690
+ }
691
+ this.listeners.set(event, remaining);
692
+ }
693
+ for (const l of this.wildcardListeners) {
694
+ l.handler({ event, data });
695
+ }
696
+ }
697
+ /** Listen to all events. */
698
+ onAny(handler) {
699
+ const listener = { handler, once: false };
700
+ this.wildcardListeners.push(listener);
701
+ return () => {
702
+ this.wildcardListeners = this.wildcardListeners.filter((l) => l !== listener);
703
+ };
704
+ }
705
+ /** Remove all listeners. */
706
+ clear() {
707
+ this.listeners.clear();
708
+ this.wildcardListeners = [];
709
+ }
710
+ /** Get count of listeners for an event (or all events). */
711
+ listenerCount(event) {
712
+ if (event) return (this.listeners.get(event) || []).length;
713
+ let total = this.wildcardListeners.length;
714
+ for (const [, list] of this.listeners) total += list.length;
715
+ return total;
716
+ }
717
+ };
718
+
719
+ // src/math.ts
720
+ var PI = Math.PI;
721
+ var TAU = Math.PI * 2;
722
+ var HALF_PI = Math.PI / 2;
723
+ var DEG_TO_RAD = Math.PI / 180;
724
+ var RAD_TO_DEG = 180 / Math.PI;
725
+ var EPSILON = 1e-6;
726
+ function clamp2(value, min, max) {
727
+ return Math.max(min, Math.min(max, value));
728
+ }
729
+ function lerp2(a, b, t) {
730
+ return a + (b - a) * t;
731
+ }
732
+ function inverseLerp(a, b, value) {
733
+ return (value - a) / (b - a);
734
+ }
735
+ function remap(value, inMin, inMax, outMin, outMax) {
736
+ return lerp2(outMin, outMax, inverseLerp(inMin, inMax, value));
737
+ }
738
+ function smoothstep(edge0, edge1, x) {
739
+ const t = clamp2((x - edge0) / (edge1 - edge0), 0, 1);
740
+ return t * t * (3 - 2 * t);
741
+ }
742
+ function smootherstep(edge0, edge1, x) {
743
+ const t = clamp2((x - edge0) / (edge1 - edge0), 0, 1);
744
+ return t * t * t * (t * (t * 6 - 15) + 10);
745
+ }
746
+ function degToRad2(degrees) {
747
+ return degrees * DEG_TO_RAD;
748
+ }
749
+ function radToDeg2(radians) {
750
+ return radians * RAD_TO_DEG;
751
+ }
752
+ function mod(n, m) {
753
+ return (n % m + m) % m;
754
+ }
755
+ function fract(x) {
756
+ return x - Math.floor(x);
757
+ }
758
+ function sign(x) {
759
+ return x > 0 ? 1 : x < 0 ? -1 : 0;
760
+ }
761
+ function step(edge, x) {
762
+ return x < edge ? 0 : 1;
763
+ }
764
+ var vec2Math = {
765
+ add: (a, b) => ({ x: a.x + b.x, y: a.y + b.y }),
766
+ sub: (a, b) => ({ x: a.x - b.x, y: a.y - b.y }),
767
+ mul: (a, s) => ({ x: a.x * s, y: a.y * s }),
768
+ div: (a, s) => ({ x: a.x / s, y: a.y / s }),
769
+ dot: (a, b) => a.x * b.x + a.y * b.y,
770
+ length: (v) => Math.sqrt(v.x * v.x + v.y * v.y),
771
+ lengthSq: (v) => v.x * v.x + v.y * v.y,
772
+ normalize: (v) => {
773
+ const len = vec2Math.length(v);
774
+ return len > 0 ? vec2Math.div(v, len) : { x: 0, y: 0 };
775
+ },
776
+ distance: (a, b) => vec2Math.length(vec2Math.sub(a, b)),
777
+ lerp: (a, b, t) => ({
778
+ x: lerp2(a.x, b.x, t),
779
+ y: lerp2(a.y, b.y, t)
780
+ }),
781
+ rotate: (v, angle) => {
782
+ const c = Math.cos(angle);
783
+ const s = Math.sin(angle);
784
+ return { x: v.x * c - v.y * s, y: v.x * s + v.y * c };
785
+ },
786
+ angle: (v) => Math.atan2(v.y, v.x),
787
+ angleBetween: (a, b) => {
788
+ return Math.acos(clamp2(vec2Math.dot(vec2Math.normalize(a), vec2Math.normalize(b)), -1, 1));
789
+ }
790
+ };
791
+ var vec3Math = {
792
+ zero: () => vec3(0, 0, 0),
793
+ one: () => vec3(1, 1, 1),
794
+ up: () => vec3(0, 1, 0),
795
+ down: () => vec3(0, -1, 0),
796
+ forward: () => vec3(0, 0, -1),
797
+ back: () => vec3(0, 0, 1),
798
+ left: () => vec3(-1, 0, 0),
799
+ right: () => vec3(1, 0, 0),
800
+ add: (a, b) => ({ x: a.x + b.x, y: a.y + b.y, z: a.z + b.z }),
801
+ sub: (a, b) => ({ x: a.x - b.x, y: a.y - b.y, z: a.z - b.z }),
802
+ mul: (a, s) => ({ x: a.x * s, y: a.y * s, z: a.z * s }),
803
+ div: (a, s) => ({ x: a.x / s, y: a.y / s, z: a.z / s }),
804
+ mulVec: (a, b) => ({ x: a.x * b.x, y: a.y * b.y, z: a.z * b.z }),
805
+ dot: (a, b) => a.x * b.x + a.y * b.y + a.z * b.z,
806
+ cross: (a, b) => ({
807
+ x: a.y * b.z - a.z * b.y,
808
+ y: a.z * b.x - a.x * b.z,
809
+ z: a.x * b.y - a.y * b.x
810
+ }),
811
+ length: (v) => Math.sqrt(v.x * v.x + v.y * v.y + v.z * v.z),
812
+ lengthSq: (v) => v.x * v.x + v.y * v.y + v.z * v.z,
813
+ normalize: (v) => {
814
+ const len = vec3Math.length(v);
815
+ return len > EPSILON ? vec3Math.div(v, len) : vec3(0, 0, 0);
816
+ },
817
+ distance: (a, b) => vec3Math.length(vec3Math.sub(a, b)),
818
+ distanceSq: (a, b) => vec3Math.lengthSq(vec3Math.sub(a, b)),
819
+ lerp: (a, b, t) => ({
820
+ x: lerp2(a.x, b.x, t),
821
+ y: lerp2(a.y, b.y, t),
822
+ z: lerp2(a.z, b.z, t)
823
+ }),
824
+ slerp: (a, b, t) => {
825
+ const dot = clamp2(vec3Math.dot(a, b), -1, 1);
826
+ const theta = Math.acos(dot) * t;
827
+ const relative = vec3Math.normalize(vec3Math.sub(b, vec3Math.mul(a, dot)));
828
+ return vec3Math.add(vec3Math.mul(a, Math.cos(theta)), vec3Math.mul(relative, Math.sin(theta)));
829
+ },
830
+ negate: (v) => ({ x: -v.x, y: -v.y, z: -v.z }),
831
+ abs: (v) => ({ x: Math.abs(v.x), y: Math.abs(v.y), z: Math.abs(v.z) }),
832
+ min: (a, b) => ({
833
+ x: Math.min(a.x, b.x),
834
+ y: Math.min(a.y, b.y),
835
+ z: Math.min(a.z, b.z)
836
+ }),
837
+ max: (a, b) => ({
838
+ x: Math.max(a.x, b.x),
839
+ y: Math.max(a.y, b.y),
840
+ z: Math.max(a.z, b.z)
841
+ }),
842
+ clamp: (v, min, max) => ({
843
+ x: clamp2(v.x, min.x, max.x),
844
+ y: clamp2(v.y, min.y, max.y),
845
+ z: clamp2(v.z, min.z, max.z)
846
+ }),
847
+ floor: (v) => ({
848
+ x: Math.floor(v.x),
849
+ y: Math.floor(v.y),
850
+ z: Math.floor(v.z)
851
+ }),
852
+ ceil: (v) => ({
853
+ x: Math.ceil(v.x),
854
+ y: Math.ceil(v.y),
855
+ z: Math.ceil(v.z)
856
+ }),
857
+ round: (v) => ({
858
+ x: Math.round(v.x),
859
+ y: Math.round(v.y),
860
+ z: Math.round(v.z)
861
+ }),
862
+ reflect: (v, normal) => {
863
+ const dot = vec3Math.dot(v, normal);
864
+ return vec3Math.sub(v, vec3Math.mul(normal, 2 * dot));
865
+ },
866
+ project: (v, onto) => {
867
+ const dot = vec3Math.dot(v, onto);
868
+ const lenSq = vec3Math.lengthSq(onto);
869
+ return vec3Math.mul(onto, dot / lenSq);
870
+ },
871
+ angle: (a, b) => {
872
+ const dot = vec3Math.dot(vec3Math.normalize(a), vec3Math.normalize(b));
873
+ return Math.acos(clamp2(dot, -1, 1));
874
+ },
875
+ equals: (a, b, epsilon = EPSILON) => {
876
+ return Math.abs(a.x - b.x) < epsilon && Math.abs(a.y - b.y) < epsilon && Math.abs(a.z - b.z) < epsilon;
877
+ }
878
+ };
879
+ var quatMath = {
880
+ identity: () => quat(0, 0, 0, 1),
881
+ fromAxisAngle: (axis, angle) => {
882
+ const halfAngle = angle / 2;
883
+ const s = Math.sin(halfAngle);
884
+ const normalized = vec3Math.normalize(axis);
885
+ return {
886
+ x: normalized.x * s,
887
+ y: normalized.y * s,
888
+ z: normalized.z * s,
889
+ w: Math.cos(halfAngle)
890
+ };
891
+ },
892
+ fromEuler: (euler) => {
893
+ const { x, y, z } = euler;
894
+ const c1 = Math.cos(degToRad2(x) / 2);
895
+ const c2 = Math.cos(degToRad2(y) / 2);
896
+ const c3 = Math.cos(degToRad2(z) / 2);
897
+ const s1 = Math.sin(degToRad2(x) / 2);
898
+ const s2 = Math.sin(degToRad2(y) / 2);
899
+ const s3 = Math.sin(degToRad2(z) / 2);
900
+ return {
901
+ x: s1 * c2 * c3 + c1 * s2 * s3,
902
+ y: c1 * s2 * c3 - s1 * c2 * s3,
903
+ z: c1 * c2 * s3 + s1 * s2 * c3,
904
+ w: c1 * c2 * c3 - s1 * s2 * s3
905
+ };
906
+ },
907
+ toEuler: (q) => {
908
+ const sinr_cosp = 2 * (q.w * q.x + q.y * q.z);
909
+ const cosr_cosp = 1 - 2 * (q.x * q.x + q.y * q.y);
910
+ const x = Math.atan2(sinr_cosp, cosr_cosp);
911
+ const sinp = 2 * (q.w * q.y - q.z * q.x);
912
+ let y;
913
+ if (Math.abs(sinp) >= 1) {
914
+ y = Math.PI / 2 * Math.sign(sinp);
915
+ } else {
916
+ y = Math.asin(sinp);
917
+ }
918
+ const siny_cosp = 2 * (q.w * q.z + q.x * q.y);
919
+ const cosy_cosp = 1 - 2 * (q.y * q.y + q.z * q.z);
920
+ const z = Math.atan2(siny_cosp, cosy_cosp);
921
+ return {
922
+ x: radToDeg2(x),
923
+ y: radToDeg2(y),
924
+ z: radToDeg2(z)
925
+ };
926
+ },
927
+ multiply: (a, b) => ({
928
+ x: a.w * b.x + a.x * b.w + a.y * b.z - a.z * b.y,
929
+ y: a.w * b.y - a.x * b.z + a.y * b.w + a.z * b.x,
930
+ z: a.w * b.z + a.x * b.y - a.y * b.x + a.z * b.w,
931
+ w: a.w * b.w - a.x * b.x - a.y * b.y - a.z * b.z
932
+ }),
933
+ conjugate: (q) => ({ x: -q.x, y: -q.y, z: -q.z, w: q.w }),
934
+ inverse: (q) => {
935
+ const lenSq = q.x * q.x + q.y * q.y + q.z * q.z + q.w * q.w;
936
+ return {
937
+ x: -q.x / lenSq,
938
+ y: -q.y / lenSq,
939
+ z: -q.z / lenSq,
940
+ w: q.w / lenSq
941
+ };
942
+ },
943
+ normalize: (q) => {
944
+ const len = Math.sqrt(q.x * q.x + q.y * q.y + q.z * q.z + q.w * q.w);
945
+ return { x: q.x / len, y: q.y / len, z: q.z / len, w: q.w / len };
946
+ },
947
+ dot: (a, b) => a.x * b.x + a.y * b.y + a.z * b.z + a.w * b.w,
948
+ slerp: (a, b, t) => {
949
+ let dot = quatMath.dot(a, b);
950
+ let bAdjusted = b;
951
+ if (dot < 0) {
952
+ bAdjusted = { x: -b.x, y: -b.y, z: -b.z, w: -b.w };
953
+ dot = -dot;
954
+ }
955
+ if (dot > 0.9995) {
956
+ return quatMath.normalize({
957
+ x: lerp2(a.x, bAdjusted.x, t),
958
+ y: lerp2(a.y, bAdjusted.y, t),
959
+ z: lerp2(a.z, bAdjusted.z, t),
960
+ w: lerp2(a.w, bAdjusted.w, t)
961
+ });
962
+ }
963
+ const theta0 = Math.acos(dot);
964
+ const theta = theta0 * t;
965
+ const sinTheta = Math.sin(theta);
966
+ const sinTheta0 = Math.sin(theta0);
967
+ const s0 = Math.cos(theta) - dot * sinTheta / sinTheta0;
968
+ const s1 = sinTheta / sinTheta0;
969
+ return {
970
+ x: a.x * s0 + bAdjusted.x * s1,
971
+ y: a.y * s0 + bAdjusted.y * s1,
972
+ z: a.z * s0 + bAdjusted.z * s1,
973
+ w: a.w * s0 + bAdjusted.w * s1
974
+ };
975
+ },
976
+ rotateVec3: (q, v) => {
977
+ const qv = { x: q.x, y: q.y, z: q.z };
978
+ const uv = vec3Math.cross(qv, v);
979
+ const uuv = vec3Math.cross(qv, uv);
980
+ return vec3Math.add(v, vec3Math.add(vec3Math.mul(uv, 2 * q.w), vec3Math.mul(uuv, 2)));
981
+ },
982
+ lookAt: (forward, up = vec3(0, 1, 0)) => {
983
+ const f = vec3Math.normalize(forward);
984
+ const r = vec3Math.normalize(vec3Math.cross(up, f));
985
+ const u = vec3Math.cross(f, r);
986
+ const trace = r.x + u.y + f.z;
987
+ let q;
988
+ if (trace > 0) {
989
+ const s = 0.5 / Math.sqrt(trace + 1);
990
+ q = {
991
+ w: 0.25 / s,
992
+ x: (u.z - f.y) * s,
993
+ y: (f.x - r.z) * s,
994
+ z: (r.y - u.x) * s
995
+ };
996
+ } else if (r.x > u.y && r.x > f.z) {
997
+ const s = 2 * Math.sqrt(1 + r.x - u.y - f.z);
998
+ q = {
999
+ w: (u.z - f.y) / s,
1000
+ x: 0.25 * s,
1001
+ y: (u.x + r.y) / s,
1002
+ z: (f.x + r.z) / s
1003
+ };
1004
+ } else if (u.y > f.z) {
1005
+ const s = 2 * Math.sqrt(1 + u.y - r.x - f.z);
1006
+ q = {
1007
+ w: (f.x - r.z) / s,
1008
+ x: (u.x + r.y) / s,
1009
+ y: 0.25 * s,
1010
+ z: (f.y + u.z) / s
1011
+ };
1012
+ } else {
1013
+ const s = 2 * Math.sqrt(1 + f.z - r.x - u.y);
1014
+ q = {
1015
+ w: (r.y - u.x) / s,
1016
+ x: (f.x + r.z) / s,
1017
+ y: (f.y + u.z) / s,
1018
+ z: 0.25 * s
1019
+ };
1020
+ }
1021
+ return quatMath.normalize(q);
1022
+ }
1023
+ };
1024
+ var aabbMath = {
1025
+ contains: (aabb2, point) => {
1026
+ return point.x >= aabb2.min.x && point.x <= aabb2.max.x && point.y >= aabb2.min.y && point.y <= aabb2.max.y && point.z >= aabb2.min.z && point.z <= aabb2.max.z;
1027
+ },
1028
+ intersects: (a, b) => {
1029
+ return a.min.x <= b.max.x && a.max.x >= b.min.x && a.min.y <= b.max.y && a.max.y >= b.min.y && a.min.z <= b.max.z && a.max.z >= b.min.z;
1030
+ },
1031
+ center: (aabb2) => vec3Math.mul(vec3Math.add(aabb2.min, aabb2.max), 0.5),
1032
+ size: (aabb2) => vec3Math.sub(aabb2.max, aabb2.min),
1033
+ expand: (aabb2, point) => ({
1034
+ min: vec3Math.min(aabb2.min, point),
1035
+ max: vec3Math.max(aabb2.max, point)
1036
+ }),
1037
+ merge: (a, b) => ({
1038
+ min: vec3Math.min(a.min, b.min),
1039
+ max: vec3Math.max(a.max, b.max)
1040
+ })
1041
+ };
1042
+ var perm = new Uint8Array(512);
1043
+ for (let i = 0; i < 256; i++) perm[i] = perm[i + 256] = i;
1044
+ for (let i = 255; i > 0; i--) {
1045
+ const j = Math.floor(Math.random() * (i + 1));
1046
+ [perm[i], perm[j]] = [perm[j], perm[i]];
1047
+ perm[i + 256] = perm[i];
1048
+ }
1049
+ function fade(t) {
1050
+ return t * t * t * (t * (t * 6 - 15) + 10);
1051
+ }
1052
+ function grad(hash, x, y, z) {
1053
+ const h = hash & 15;
1054
+ const u = h < 8 ? x : y;
1055
+ const v = h < 4 ? y : h === 12 || h === 14 ? x : z;
1056
+ return ((h & 1) === 0 ? u : -u) + ((h & 2) === 0 ? v : -v);
1057
+ }
1058
+ var noise = {
1059
+ /**
1060
+ * 3D Perlin noise (-1 to 1)
1061
+ */
1062
+ perlin3d: (x, y, z) => {
1063
+ const X = Math.floor(x) & 255;
1064
+ const Y = Math.floor(y) & 255;
1065
+ const Z = Math.floor(z) & 255;
1066
+ x -= Math.floor(x);
1067
+ y -= Math.floor(y);
1068
+ z -= Math.floor(z);
1069
+ const u = fade(x);
1070
+ const v = fade(y);
1071
+ const w = fade(z);
1072
+ const A = perm[X] + Y;
1073
+ const AA = perm[A] + Z;
1074
+ const AB = perm[A + 1] + Z;
1075
+ const B = perm[X + 1] + Y;
1076
+ const BA = perm[B] + Z;
1077
+ const BB = perm[B + 1] + Z;
1078
+ return lerp2(
1079
+ lerp2(
1080
+ lerp2(grad(perm[AA], x, y, z), grad(perm[BA], x - 1, y, z), u),
1081
+ lerp2(grad(perm[AB], x, y - 1, z), grad(perm[BB], x - 1, y - 1, z), u),
1082
+ v
1083
+ ),
1084
+ lerp2(
1085
+ lerp2(grad(perm[AA + 1], x, y, z - 1), grad(perm[BA + 1], x - 1, y, z - 1), u),
1086
+ lerp2(grad(perm[AB + 1], x, y - 1, z - 1), grad(perm[BB + 1], x - 1, y - 1, z - 1), u),
1087
+ v
1088
+ ),
1089
+ w
1090
+ );
1091
+ },
1092
+ /**
1093
+ * 2D Perlin noise (-1 to 1)
1094
+ */
1095
+ perlin2d: (x, y) => {
1096
+ return noise.perlin3d(x, y, 0);
1097
+ },
1098
+ /**
1099
+ * Fractal Brownian Motion (fBm)
1100
+ */
1101
+ fbm: (x, y, z, octaves = 6, lacunarity = 2, gain = 0.5) => {
1102
+ let value = 0;
1103
+ let amplitude = 1;
1104
+ let frequency = 1;
1105
+ let maxValue = 0;
1106
+ for (let i = 0; i < octaves; i++) {
1107
+ value += amplitude * noise.perlin3d(x * frequency, y * frequency, z * frequency);
1108
+ maxValue += amplitude;
1109
+ amplitude *= gain;
1110
+ frequency *= lacunarity;
1111
+ }
1112
+ return value / maxValue;
1113
+ },
1114
+ /**
1115
+ * Simplex-like noise (approximation using perlin)
1116
+ */
1117
+ simplex: (x, y) => {
1118
+ return noise.perlin2d(x * 1.2, y * 1.2);
1119
+ },
1120
+ /**
1121
+ * Worley/Cellular noise
1122
+ */
1123
+ worley: (x, y, z) => {
1124
+ const xi = Math.floor(x);
1125
+ const yi = Math.floor(y);
1126
+ const zi = Math.floor(z);
1127
+ let minDist = Infinity;
1128
+ for (let i = -1; i <= 1; i++) {
1129
+ for (let j = -1; j <= 1; j++) {
1130
+ for (let k = -1; k <= 1; k++) {
1131
+ const cellX = xi + i;
1132
+ const cellY = yi + j;
1133
+ const cellZ = zi + k;
1134
+ const hash = perm[perm[perm[cellX & 255] + cellY & 255] + cellZ & 255];
1135
+ const px = cellX + hash / 255;
1136
+ const py = cellY + hash * 7 % 255 / 255;
1137
+ const pz = cellZ + hash * 13 % 255 / 255;
1138
+ const dist = (x - px) * (x - px) + (y - py) * (y - py) + (z - pz) * (z - pz);
1139
+ minDist = Math.min(minDist, dist);
1140
+ }
1141
+ }
1142
+ }
1143
+ return Math.sqrt(minDist);
1144
+ }
1145
+ };
1146
+ var random = {
1147
+ /**
1148
+ * Random float between 0 and 1
1149
+ */
1150
+ float: () => Math.random(),
1151
+ /**
1152
+ * Random float in range [min, max)
1153
+ */
1154
+ range: (min, max) => min + Math.random() * (max - min),
1155
+ /**
1156
+ * Random integer in range [min, max]
1157
+ */
1158
+ int: (min, max) => Math.floor(min + Math.random() * (max - min + 1)),
1159
+ /**
1160
+ * Random boolean with probability
1161
+ */
1162
+ bool: (probability = 0.5) => Math.random() < probability,
1163
+ /**
1164
+ * Random element from array
1165
+ */
1166
+ pick: (array) => array[Math.floor(Math.random() * array.length)],
1167
+ /**
1168
+ * Shuffle array (Fisher-Yates)
1169
+ */
1170
+ shuffle: (array) => {
1171
+ const result = [...array];
1172
+ for (let i = result.length - 1; i > 0; i--) {
1173
+ const j = Math.floor(Math.random() * (i + 1));
1174
+ [result[i], result[j]] = [result[j], result[i]];
1175
+ }
1176
+ return result;
1177
+ },
1178
+ /**
1179
+ * Random Vec3 in unit sphere
1180
+ */
1181
+ insideUnitSphere: () => {
1182
+ const theta = Math.random() * TAU;
1183
+ const phi = Math.acos(2 * Math.random() - 1);
1184
+ const r = Math.cbrt(Math.random());
1185
+ return {
1186
+ x: r * Math.sin(phi) * Math.cos(theta),
1187
+ y: r * Math.sin(phi) * Math.sin(theta),
1188
+ z: r * Math.cos(phi)
1189
+ };
1190
+ },
1191
+ /**
1192
+ * Random Vec3 on unit sphere surface
1193
+ */
1194
+ onUnitSphere: () => {
1195
+ const theta = Math.random() * TAU;
1196
+ const phi = Math.acos(2 * Math.random() - 1);
1197
+ return {
1198
+ x: Math.sin(phi) * Math.cos(theta),
1199
+ y: Math.sin(phi) * Math.sin(theta),
1200
+ z: Math.cos(phi)
1201
+ };
1202
+ },
1203
+ /**
1204
+ * Random Vec2 in unit circle
1205
+ */
1206
+ insideUnitCircle: () => {
1207
+ const theta = Math.random() * TAU;
1208
+ const r = Math.sqrt(Math.random());
1209
+ return {
1210
+ x: r * Math.cos(theta),
1211
+ y: r * Math.sin(theta)
1212
+ };
1213
+ },
1214
+ /**
1215
+ * Seeded random number generator
1216
+ */
1217
+ seeded: (seed) => {
1218
+ let s = seed;
1219
+ return () => {
1220
+ s = s * 1103515245 + 12345 & 2147483647;
1221
+ return s / 2147483647;
1222
+ };
1223
+ }
1224
+ };
1225
+
1226
+ // src/collections.ts
1227
+ var List = class _List {
1228
+ items;
1229
+ constructor(items = []) {
1230
+ this.items = Array.from(items);
1231
+ }
1232
+ static of(...items) {
1233
+ return new _List(items);
1234
+ }
1235
+ static from(iterable) {
1236
+ return new _List(iterable);
1237
+ }
1238
+ static range(start, end, step2 = 1) {
1239
+ const items = [];
1240
+ for (let i = start; step2 > 0 ? i < end : i > end; i += step2) {
1241
+ items.push(i);
1242
+ }
1243
+ return new _List(items);
1244
+ }
1245
+ static repeat(value, count2) {
1246
+ return new _List(Array(count2).fill(value));
1247
+ }
1248
+ get length() {
1249
+ return this.items.length;
1250
+ }
1251
+ get isEmpty() {
1252
+ return this.items.length === 0;
1253
+ }
1254
+ get(index) {
1255
+ return index < 0 ? this.items[this.items.length + index] : this.items[index];
1256
+ }
1257
+ first() {
1258
+ return this.items[0];
1259
+ }
1260
+ last() {
1261
+ return this.items[this.items.length - 1];
1262
+ }
1263
+ map(fn) {
1264
+ return new _List(this.items.map(fn));
1265
+ }
1266
+ flatMap(fn) {
1267
+ const result = [];
1268
+ this.items.forEach((item, index) => {
1269
+ const mapped = fn(item, index);
1270
+ if (mapped instanceof _List) {
1271
+ result.push(...mapped.toArray());
1272
+ } else {
1273
+ result.push(...mapped);
1274
+ }
1275
+ });
1276
+ return new _List(result);
1277
+ }
1278
+ filter(predicate) {
1279
+ return new _List(this.items.filter(predicate));
1280
+ }
1281
+ reject(predicate) {
1282
+ return this.filter((item, index) => !predicate(item, index));
1283
+ }
1284
+ reduce(fn, initial) {
1285
+ return this.items.reduce(fn, initial);
1286
+ }
1287
+ fold(initial, fn) {
1288
+ return this.items.reduce(fn, initial);
1289
+ }
1290
+ find(predicate) {
1291
+ return this.items.find(predicate);
1292
+ }
1293
+ findIndex(predicate) {
1294
+ return this.items.findIndex(predicate);
1295
+ }
1296
+ indexOf(item) {
1297
+ return this.items.indexOf(item);
1298
+ }
1299
+ includes(item) {
1300
+ return this.items.includes(item);
1301
+ }
1302
+ some(predicate) {
1303
+ return this.items.some(predicate);
1304
+ }
1305
+ every(predicate) {
1306
+ return this.items.every(predicate);
1307
+ }
1308
+ none(predicate) {
1309
+ return !this.some(predicate);
1310
+ }
1311
+ count(predicate) {
1312
+ return this.filter(predicate).length;
1313
+ }
1314
+ forEach(fn) {
1315
+ this.items.forEach(fn);
1316
+ }
1317
+ concat(...lists) {
1318
+ const arrays = lists.map((l) => l instanceof _List ? l.toArray() : l);
1319
+ return new _List([...this.items, ...arrays.flat()]);
1320
+ }
1321
+ append(item) {
1322
+ return new _List([...this.items, item]);
1323
+ }
1324
+ prepend(item) {
1325
+ return new _List([item, ...this.items]);
1326
+ }
1327
+ insert(index, item) {
1328
+ const arr = [...this.items];
1329
+ arr.splice(index, 0, item);
1330
+ return new _List(arr);
1331
+ }
1332
+ remove(index) {
1333
+ const arr = [...this.items];
1334
+ arr.splice(index, 1);
1335
+ return new _List(arr);
1336
+ }
1337
+ update(index, item) {
1338
+ const arr = [...this.items];
1339
+ arr[index] = item;
1340
+ return new _List(arr);
1341
+ }
1342
+ slice(start, end) {
1343
+ return new _List(this.items.slice(start, end));
1344
+ }
1345
+ take(n) {
1346
+ return this.slice(0, n);
1347
+ }
1348
+ takeLast(n) {
1349
+ return this.slice(-n);
1350
+ }
1351
+ takeWhile(predicate) {
1352
+ const result = [];
1353
+ for (let i = 0; i < this.items.length; i++) {
1354
+ if (!predicate(this.items[i], i)) break;
1355
+ result.push(this.items[i]);
1356
+ }
1357
+ return new _List(result);
1358
+ }
1359
+ drop(n) {
1360
+ return this.slice(n);
1361
+ }
1362
+ dropLast(n) {
1363
+ return this.slice(0, -n);
1364
+ }
1365
+ dropWhile(predicate) {
1366
+ let startIndex = 0;
1367
+ for (let i = 0; i < this.items.length; i++) {
1368
+ if (!predicate(this.items[i], i)) break;
1369
+ startIndex = i + 1;
1370
+ }
1371
+ return this.slice(startIndex);
1372
+ }
1373
+ reverse() {
1374
+ return new _List([...this.items].reverse());
1375
+ }
1376
+ sort(compareFn) {
1377
+ return new _List([...this.items].sort(compareFn));
1378
+ }
1379
+ sortBy(fn) {
1380
+ return this.sort((a, b) => {
1381
+ const va = fn(a);
1382
+ const vb = fn(b);
1383
+ if (va < vb) return -1;
1384
+ if (va > vb) return 1;
1385
+ return 0;
1386
+ });
1387
+ }
1388
+ shuffle() {
1389
+ const arr = [...this.items];
1390
+ for (let i = arr.length - 1; i > 0; i--) {
1391
+ const j = Math.floor(Math.random() * (i + 1));
1392
+ [arr[i], arr[j]] = [arr[j], arr[i]];
1393
+ }
1394
+ return new _List(arr);
1395
+ }
1396
+ unique() {
1397
+ return new _List([...new Set(this.items)]);
1398
+ }
1399
+ uniqueBy(fn) {
1400
+ const seen = /* @__PURE__ */ new Set();
1401
+ const result = [];
1402
+ for (const item of this.items) {
1403
+ const key = fn(item);
1404
+ if (!seen.has(key)) {
1405
+ seen.add(key);
1406
+ result.push(item);
1407
+ }
1408
+ }
1409
+ return new _List(result);
1410
+ }
1411
+ groupBy(fn) {
1412
+ const groups = /* @__PURE__ */ new Map();
1413
+ for (const item of this.items) {
1414
+ const key = fn(item);
1415
+ const group = groups.get(key) || [];
1416
+ group.push(item);
1417
+ groups.set(key, group);
1418
+ }
1419
+ const result = /* @__PURE__ */ new Map();
1420
+ for (const [key, items] of groups) {
1421
+ result.set(key, new _List(items));
1422
+ }
1423
+ return new HoloMap(result);
1424
+ }
1425
+ partition(predicate) {
1426
+ const pass = [];
1427
+ const fail = [];
1428
+ this.items.forEach((item, index) => {
1429
+ if (predicate(item, index)) {
1430
+ pass.push(item);
1431
+ } else {
1432
+ fail.push(item);
1433
+ }
1434
+ });
1435
+ return [new _List(pass), new _List(fail)];
1436
+ }
1437
+ zip(other) {
1438
+ const length = Math.min(this.length, other.length);
1439
+ const result = [];
1440
+ for (let i = 0; i < length; i++) {
1441
+ result.push([this.items[i], other.get(i)]);
1442
+ }
1443
+ return new _List(result);
1444
+ }
1445
+ zipWith(other, fn) {
1446
+ return this.zip(other).map(([a, b]) => fn(a, b));
1447
+ }
1448
+ flatten() {
1449
+ const result = [];
1450
+ for (const item of this.items) {
1451
+ if (item instanceof _List) {
1452
+ result.push(...item.toArray());
1453
+ } else if (Array.isArray(item)) {
1454
+ result.push(...item);
1455
+ }
1456
+ }
1457
+ return new _List(result);
1458
+ }
1459
+ sum() {
1460
+ return this.reduce((acc, n) => acc + n, 0);
1461
+ }
1462
+ min() {
1463
+ if (this.isEmpty) return void 0;
1464
+ return Math.min(...this.items);
1465
+ }
1466
+ max() {
1467
+ if (this.isEmpty) return void 0;
1468
+ return Math.max(...this.items);
1469
+ }
1470
+ average() {
1471
+ if (this.isEmpty) return void 0;
1472
+ return this.sum() / this.length;
1473
+ }
1474
+ join(separator = ",") {
1475
+ return this.items.join(separator);
1476
+ }
1477
+ toArray() {
1478
+ return [...this.items];
1479
+ }
1480
+ toSet() {
1481
+ return new HoloSet(this.items);
1482
+ }
1483
+ [Symbol.iterator]() {
1484
+ return this.items[Symbol.iterator]();
1485
+ }
1486
+ toString() {
1487
+ return `List(${this.items.join(", ")})`;
1488
+ }
1489
+ };
1490
+ var HoloMap = class _HoloMap {
1491
+ _map;
1492
+ constructor(entries) {
1493
+ this._map = entries instanceof Map ? entries : new Map(entries);
1494
+ }
1495
+ static of(...entries) {
1496
+ return new _HoloMap(entries);
1497
+ }
1498
+ static from(entries) {
1499
+ return new _HoloMap(entries);
1500
+ }
1501
+ static fromObject(obj) {
1502
+ return new _HoloMap(Object.entries(obj));
1503
+ }
1504
+ get size() {
1505
+ return this._map.size;
1506
+ }
1507
+ get isEmpty() {
1508
+ return this._map.size === 0;
1509
+ }
1510
+ get(key) {
1511
+ return this._map.get(key);
1512
+ }
1513
+ getOrDefault(key, defaultValue) {
1514
+ return this._map.has(key) ? this._map.get(key) : defaultValue;
1515
+ }
1516
+ has(key) {
1517
+ return this._map.has(key);
1518
+ }
1519
+ set(key, value) {
1520
+ const newMap = new Map(this._map);
1521
+ newMap.set(key, value);
1522
+ return new _HoloMap(newMap);
1523
+ }
1524
+ delete(key) {
1525
+ const newMap = new Map(this._map);
1526
+ newMap.delete(key);
1527
+ return new _HoloMap(newMap);
1528
+ }
1529
+ update(key, fn) {
1530
+ return this.set(key, fn(this.get(key)));
1531
+ }
1532
+ merge(other) {
1533
+ const newMap = new Map(this._map);
1534
+ for (const [key, value] of other) {
1535
+ newMap.set(key, value);
1536
+ }
1537
+ return new _HoloMap(newMap);
1538
+ }
1539
+ keys() {
1540
+ return new List(this._map.keys());
1541
+ }
1542
+ values() {
1543
+ return new List(this._map.values());
1544
+ }
1545
+ entries() {
1546
+ return new List(this._map.entries());
1547
+ }
1548
+ map(fn) {
1549
+ const entries = [];
1550
+ for (const [key, value] of this._map) {
1551
+ entries.push([key, fn(value, key)]);
1552
+ }
1553
+ return new _HoloMap(entries);
1554
+ }
1555
+ mapKeys(fn) {
1556
+ const entries = [];
1557
+ for (const [key, value] of this._map) {
1558
+ entries.push([fn(key, value), value]);
1559
+ }
1560
+ return new _HoloMap(entries);
1561
+ }
1562
+ filter(predicate) {
1563
+ const entries = [];
1564
+ for (const [key, value] of this._map) {
1565
+ if (predicate(value, key)) {
1566
+ entries.push([key, value]);
1567
+ }
1568
+ }
1569
+ return new _HoloMap(entries);
1570
+ }
1571
+ reduce(fn, initial) {
1572
+ let acc = initial;
1573
+ for (const [key, value] of this._map) {
1574
+ acc = fn(acc, value, key);
1575
+ }
1576
+ return acc;
1577
+ }
1578
+ forEach(fn) {
1579
+ this._map.forEach(fn);
1580
+ }
1581
+ find(predicate) {
1582
+ for (const [key, value] of this._map) {
1583
+ if (predicate(value, key)) {
1584
+ return [key, value];
1585
+ }
1586
+ }
1587
+ return void 0;
1588
+ }
1589
+ some(predicate) {
1590
+ for (const [key, value] of this._map) {
1591
+ if (predicate(value, key)) return true;
1592
+ }
1593
+ return false;
1594
+ }
1595
+ every(predicate) {
1596
+ for (const [key, value] of this._map) {
1597
+ if (!predicate(value, key)) return false;
1598
+ }
1599
+ return true;
1600
+ }
1601
+ toObject() {
1602
+ const obj = {};
1603
+ for (const [key, value] of this._map) {
1604
+ obj[key] = value;
1605
+ }
1606
+ return obj;
1607
+ }
1608
+ toNativeMap() {
1609
+ return new Map(this._map);
1610
+ }
1611
+ [Symbol.iterator]() {
1612
+ return this._map[Symbol.iterator]();
1613
+ }
1614
+ toString() {
1615
+ const entries = [...this._map].map(([k, v]) => `${k}: ${v}`).join(", ");
1616
+ return `HoloMap { ${entries} }`;
1617
+ }
1618
+ };
1619
+ var HoloSet = class _HoloSet {
1620
+ set;
1621
+ constructor(items) {
1622
+ this.set = new Set(items);
1623
+ }
1624
+ static of(...items) {
1625
+ return new _HoloSet(items);
1626
+ }
1627
+ static from(iterable) {
1628
+ return new _HoloSet(iterable);
1629
+ }
1630
+ get size() {
1631
+ return this.set.size;
1632
+ }
1633
+ get isEmpty() {
1634
+ return this.set.size === 0;
1635
+ }
1636
+ has(item) {
1637
+ return this.set.has(item);
1638
+ }
1639
+ add(item) {
1640
+ const newSet = new Set(this.set);
1641
+ newSet.add(item);
1642
+ return new _HoloSet(newSet);
1643
+ }
1644
+ delete(item) {
1645
+ const newSet = new Set(this.set);
1646
+ newSet.delete(item);
1647
+ return new _HoloSet(newSet);
1648
+ }
1649
+ addAll(items) {
1650
+ const newSet = new Set(this.set);
1651
+ for (const item of items) {
1652
+ newSet.add(item);
1653
+ }
1654
+ return new _HoloSet(newSet);
1655
+ }
1656
+ union(other) {
1657
+ return this.addAll(other);
1658
+ }
1659
+ intersection(other) {
1660
+ const result = /* @__PURE__ */ new Set();
1661
+ for (const item of this.set) {
1662
+ if (other.has(item)) {
1663
+ result.add(item);
1664
+ }
1665
+ }
1666
+ return new _HoloSet(result);
1667
+ }
1668
+ difference(other) {
1669
+ const result = /* @__PURE__ */ new Set();
1670
+ for (const item of this.set) {
1671
+ if (!other.has(item)) {
1672
+ result.add(item);
1673
+ }
1674
+ }
1675
+ return new _HoloSet(result);
1676
+ }
1677
+ symmetricDifference(other) {
1678
+ return this.difference(other).union(other.difference(this));
1679
+ }
1680
+ isSubsetOf(other) {
1681
+ for (const item of this.set) {
1682
+ if (!other.has(item)) return false;
1683
+ }
1684
+ return true;
1685
+ }
1686
+ isSupersetOf(other) {
1687
+ return other.isSubsetOf(this);
1688
+ }
1689
+ isDisjointFrom(other) {
1690
+ return this.intersection(other).isEmpty;
1691
+ }
1692
+ map(fn) {
1693
+ const result = /* @__PURE__ */ new Set();
1694
+ for (const item of this.set) {
1695
+ result.add(fn(item));
1696
+ }
1697
+ return new _HoloSet(result);
1698
+ }
1699
+ filter(predicate) {
1700
+ const result = /* @__PURE__ */ new Set();
1701
+ for (const item of this.set) {
1702
+ if (predicate(item)) {
1703
+ result.add(item);
1704
+ }
1705
+ }
1706
+ return new _HoloSet(result);
1707
+ }
1708
+ reduce(fn, initial) {
1709
+ let acc = initial;
1710
+ for (const item of this.set) {
1711
+ acc = fn(acc, item);
1712
+ }
1713
+ return acc;
1714
+ }
1715
+ forEach(fn) {
1716
+ this.set.forEach(fn);
1717
+ }
1718
+ find(predicate) {
1719
+ for (const item of this.set) {
1720
+ if (predicate(item)) return item;
1721
+ }
1722
+ return void 0;
1723
+ }
1724
+ some(predicate) {
1725
+ for (const item of this.set) {
1726
+ if (predicate(item)) return true;
1727
+ }
1728
+ return false;
1729
+ }
1730
+ every(predicate) {
1731
+ for (const item of this.set) {
1732
+ if (!predicate(item)) return false;
1733
+ }
1734
+ return true;
1735
+ }
1736
+ toArray() {
1737
+ return [...this.set];
1738
+ }
1739
+ toList() {
1740
+ return new List(this.set);
1741
+ }
1742
+ toNativeSet() {
1743
+ return new Set(this.set);
1744
+ }
1745
+ [Symbol.iterator]() {
1746
+ return this.set[Symbol.iterator]();
1747
+ }
1748
+ toString() {
1749
+ return `HoloSet { ${[...this.set].join(", ")} }`;
1750
+ }
1751
+ };
1752
+ var SpatialGrid = class {
1753
+ cellSize;
1754
+ cells = /* @__PURE__ */ new Map();
1755
+ constructor(cellSize) {
1756
+ this.cellSize = cellSize;
1757
+ }
1758
+ getCellKey(x, y, z) {
1759
+ const cx = Math.floor(x / this.cellSize);
1760
+ const cy = Math.floor(y / this.cellSize);
1761
+ const cz = Math.floor(z / this.cellSize);
1762
+ return `${cx},${cy},${cz}`;
1763
+ }
1764
+ insert(position, item) {
1765
+ const key = this.getCellKey(position.x, position.y, position.z);
1766
+ if (!this.cells.has(key)) {
1767
+ this.cells.set(key, []);
1768
+ }
1769
+ this.cells.get(key).push(item);
1770
+ }
1771
+ remove(position, item) {
1772
+ const key = this.getCellKey(position.x, position.y, position.z);
1773
+ const cell = this.cells.get(key);
1774
+ if (!cell) return false;
1775
+ const index = cell.indexOf(item);
1776
+ if (index === -1) return false;
1777
+ cell.splice(index, 1);
1778
+ if (cell.length === 0) {
1779
+ this.cells.delete(key);
1780
+ }
1781
+ return true;
1782
+ }
1783
+ query(center2, radius) {
1784
+ const results = [];
1785
+ const cellRadius = Math.ceil(radius / this.cellSize);
1786
+ const cx = Math.floor(center2.x / this.cellSize);
1787
+ const cy = Math.floor(center2.y / this.cellSize);
1788
+ const cz = Math.floor(center2.z / this.cellSize);
1789
+ for (let x = cx - cellRadius; x <= cx + cellRadius; x++) {
1790
+ for (let y = cy - cellRadius; y <= cy + cellRadius; y++) {
1791
+ for (let z = cz - cellRadius; z <= cz + cellRadius; z++) {
1792
+ const cell = this.cells.get(`${x},${y},${z}`);
1793
+ if (cell) {
1794
+ results.push(...cell);
1795
+ }
1796
+ }
1797
+ }
1798
+ }
1799
+ return results;
1800
+ }
1801
+ queryBox(min, max) {
1802
+ const results = [];
1803
+ const minCx = Math.floor(min.x / this.cellSize);
1804
+ const minCy = Math.floor(min.y / this.cellSize);
1805
+ const minCz = Math.floor(min.z / this.cellSize);
1806
+ const maxCx = Math.floor(max.x / this.cellSize);
1807
+ const maxCy = Math.floor(max.y / this.cellSize);
1808
+ const maxCz = Math.floor(max.z / this.cellSize);
1809
+ for (let x = minCx; x <= maxCx; x++) {
1810
+ for (let y = minCy; y <= maxCy; y++) {
1811
+ for (let z = minCz; z <= maxCz; z++) {
1812
+ const cell = this.cells.get(`${x},${y},${z}`);
1813
+ if (cell) {
1814
+ results.push(...cell);
1815
+ }
1816
+ }
1817
+ }
1818
+ }
1819
+ return results;
1820
+ }
1821
+ clear() {
1822
+ this.cells.clear();
1823
+ }
1824
+ get cellCount() {
1825
+ return this.cells.size;
1826
+ }
1827
+ get itemCount() {
1828
+ let count2 = 0;
1829
+ for (const cell of this.cells.values()) {
1830
+ count2 += cell.length;
1831
+ }
1832
+ return count2;
1833
+ }
1834
+ };
1835
+ var PriorityQueue = class _PriorityQueue {
1836
+ constructor(compareFn = (a, b) => a - b) {
1837
+ this.compareFn = compareFn;
1838
+ }
1839
+ heap = [];
1840
+ static minHeap() {
1841
+ return new _PriorityQueue((a, b) => a - b);
1842
+ }
1843
+ static maxHeap() {
1844
+ return new _PriorityQueue((a, b) => b - a);
1845
+ }
1846
+ get size() {
1847
+ return this.heap.length;
1848
+ }
1849
+ get isEmpty() {
1850
+ return this.heap.length === 0;
1851
+ }
1852
+ enqueue(item, priority) {
1853
+ this.heap.push({ item, priority });
1854
+ this.bubbleUp(this.heap.length - 1);
1855
+ }
1856
+ dequeue() {
1857
+ if (this.isEmpty) return void 0;
1858
+ const result = this.heap[0].item;
1859
+ const last = this.heap.pop();
1860
+ if (this.heap.length > 0) {
1861
+ this.heap[0] = last;
1862
+ this.bubbleDown(0);
1863
+ }
1864
+ return result;
1865
+ }
1866
+ peek() {
1867
+ return this.heap[0]?.item;
1868
+ }
1869
+ peekPriority() {
1870
+ return this.heap[0]?.priority;
1871
+ }
1872
+ clear() {
1873
+ this.heap = [];
1874
+ }
1875
+ bubbleUp(index) {
1876
+ while (index > 0) {
1877
+ const parentIndex = Math.floor((index - 1) / 2);
1878
+ if (this.compareFn(this.heap[index].priority, this.heap[parentIndex].priority) >= 0) break;
1879
+ [this.heap[index], this.heap[parentIndex]] = [this.heap[parentIndex], this.heap[index]];
1880
+ index = parentIndex;
1881
+ }
1882
+ }
1883
+ bubbleDown(index) {
1884
+ while (true) {
1885
+ const leftChild = 2 * index + 1;
1886
+ const rightChild = 2 * index + 2;
1887
+ let smallest = index;
1888
+ if (leftChild < this.heap.length && this.compareFn(this.heap[leftChild].priority, this.heap[smallest].priority) < 0) {
1889
+ smallest = leftChild;
1890
+ }
1891
+ if (rightChild < this.heap.length && this.compareFn(this.heap[rightChild].priority, this.heap[smallest].priority) < 0) {
1892
+ smallest = rightChild;
1893
+ }
1894
+ if (smallest === index) break;
1895
+ [this.heap[index], this.heap[smallest]] = [this.heap[smallest], this.heap[index]];
1896
+ index = smallest;
1897
+ }
1898
+ }
1899
+ };
1900
+
1901
+ // src/string.ts
1902
+ function isBlank(s) {
1903
+ return s.trim().length === 0;
1904
+ }
1905
+ function isNotBlank(s) {
1906
+ return s.trim().length > 0;
1907
+ }
1908
+ function capitalize(s) {
1909
+ if (s.length === 0) return s;
1910
+ return s[0].toUpperCase() + s.slice(1);
1911
+ }
1912
+ function titleCase(s) {
1913
+ return s.split(/\s+/).map(capitalize).join(" ");
1914
+ }
1915
+ function camelCase(s) {
1916
+ return s.replace(/[-_\s]+(.)?/g, (_, c) => c ? c.toUpperCase() : "").replace(/^[A-Z]/, (c) => c.toLowerCase());
1917
+ }
1918
+ function pascalCase(s) {
1919
+ const camel = camelCase(s);
1920
+ return camel.length > 0 ? camel[0].toUpperCase() + camel.slice(1) : camel;
1921
+ }
1922
+ function snakeCase(s) {
1923
+ return s.replace(/([a-z])([A-Z])/g, "$1_$2").replace(/[-\s]+/g, "_").toLowerCase();
1924
+ }
1925
+ function kebabCase(s) {
1926
+ return s.replace(/([a-z])([A-Z])/g, "$1-$2").replace(/[_\s]+/g, "-").toLowerCase();
1927
+ }
1928
+ function constantCase(s) {
1929
+ return snakeCase(s).toUpperCase();
1930
+ }
1931
+ function padLeft(s, length, char = " ") {
1932
+ return s.padStart(length, char);
1933
+ }
1934
+ function padRight(s, length, char = " ") {
1935
+ return s.padEnd(length, char);
1936
+ }
1937
+ function center(s, length, char = " ") {
1938
+ if (s.length >= length) return s;
1939
+ const totalPadding = length - s.length;
1940
+ const leftPadding = Math.floor(totalPadding / 2);
1941
+ const rightPadding = totalPadding - leftPadding;
1942
+ return char.repeat(leftPadding) + s + char.repeat(rightPadding);
1943
+ }
1944
+ function truncate(s, maxLength, ellipsis = "...") {
1945
+ if (s.length <= maxLength) return s;
1946
+ return s.slice(0, maxLength - ellipsis.length) + ellipsis;
1947
+ }
1948
+ function truncateMiddle(s, maxLength, ellipsis = "...") {
1949
+ if (s.length <= maxLength) return s;
1950
+ const availableLength = maxLength - ellipsis.length;
1951
+ const leftLength = Math.floor(availableLength / 2);
1952
+ const rightLength = Math.ceil(availableLength / 2);
1953
+ return s.slice(0, leftLength) + ellipsis + s.slice(-rightLength);
1954
+ }
1955
+ function repeat(s, count2) {
1956
+ return s.repeat(count2);
1957
+ }
1958
+ function reverse(s) {
1959
+ return [...s].reverse().join("");
1960
+ }
1961
+ function count(s, substring) {
1962
+ if (substring.length === 0) return 0;
1963
+ let count2 = 0;
1964
+ let pos = 0;
1965
+ while ((pos = s.indexOf(substring, pos)) !== -1) {
1966
+ count2++;
1967
+ pos += 1;
1968
+ }
1969
+ return count2;
1970
+ }
1971
+ function containsIgnoreCase(s, substring) {
1972
+ return s.toLowerCase().includes(substring.toLowerCase());
1973
+ }
1974
+ function startsWithIgnoreCase(s, prefix) {
1975
+ return s.toLowerCase().startsWith(prefix.toLowerCase());
1976
+ }
1977
+ function endsWithIgnoreCase(s, suffix) {
1978
+ return s.toLowerCase().endsWith(suffix.toLowerCase());
1979
+ }
1980
+ function removeWhitespace(s) {
1981
+ return s.replace(/\s+/g, "");
1982
+ }
1983
+ function collapseWhitespace(s) {
1984
+ return s.replace(/\s+/g, " ").trim();
1985
+ }
1986
+ function removePrefix(s, prefix) {
1987
+ return s.startsWith(prefix) ? s.slice(prefix.length) : s;
1988
+ }
1989
+ function removeSuffix(s, suffix) {
1990
+ return s.endsWith(suffix) ? s.slice(0, -suffix.length) : s;
1991
+ }
1992
+ function wrap(s, prefixOrWrapper, suffix) {
1993
+ if (suffix === void 0) {
1994
+ return prefixOrWrapper + s + prefixOrWrapper;
1995
+ }
1996
+ return prefixOrWrapper + s + suffix;
1997
+ }
1998
+ function unwrap(s, prefixOrWrapper, suffix) {
1999
+ const prefix = prefixOrWrapper;
2000
+ const actualSuffix = suffix ?? prefixOrWrapper;
2001
+ if (s.startsWith(prefix) && s.endsWith(actualSuffix)) {
2002
+ return s.slice(prefix.length, -actualSuffix.length || void 0);
2003
+ }
2004
+ return s;
2005
+ }
2006
+ function lines(s) {
2007
+ return s.split(/\r?\n/);
2008
+ }
2009
+ function words(s) {
2010
+ return s.split(/\s+/).filter((w) => w.length > 0);
2011
+ }
2012
+ function chars(s) {
2013
+ return [...s];
2014
+ }
2015
+ function join(strings, separator = "") {
2016
+ return strings.join(separator);
2017
+ }
2018
+ function format(template, values) {
2019
+ return template.replace(/\{(\w+)\}/g, (match, key) => {
2020
+ return key in values ? String(values[key]) : match;
2021
+ });
2022
+ }
2023
+ function formatNumber(n, options = {}) {
2024
+ return n.toLocaleString("en-US", options);
2025
+ }
2026
+ function numberWithCommas(n) {
2027
+ return n.toLocaleString("en-US");
2028
+ }
2029
+ function formatBytes(bytes, decimals = 2) {
2030
+ if (bytes === 0) return "0 B";
2031
+ const k = 1024;
2032
+ if (bytes < 0) return `${bytes} B`;
2033
+ const sizes = ["B", "KB", "MB", "GB", "TB", "PB"];
2034
+ const i = Math.floor(Math.log(bytes) / Math.log(k));
2035
+ return parseFloat((bytes / Math.pow(k, i)).toFixed(decimals)) + " " + sizes[i];
2036
+ }
2037
+ function formatDuration(ms) {
2038
+ if (ms < 1e3) return `${ms}ms`;
2039
+ if (ms < 6e4) return `${(ms / 1e3).toFixed(1)}s`;
2040
+ if (ms < 36e5) {
2041
+ return `${(ms / 6e4).toFixed(1)}m`;
2042
+ }
2043
+ const hours = Math.floor(ms / 36e5);
2044
+ const mins = Math.floor(ms % 36e5 / 6e4);
2045
+ return `${(ms / 36e5).toFixed(1)}h`;
2046
+ }
2047
+ function escapeHtml(s) {
2048
+ const htmlEntities = {
2049
+ "&": "&amp;",
2050
+ "<": "&lt;",
2051
+ ">": "&gt;",
2052
+ '"': "&quot;",
2053
+ "'": "&#39;"
2054
+ };
2055
+ return s.replace(/[&<>"']/g, (c) => htmlEntities[c]);
2056
+ }
2057
+ function unescapeHtml(s) {
2058
+ const htmlEntities = {
2059
+ "&amp;": "&",
2060
+ "&lt;": "<",
2061
+ "&gt;": ">",
2062
+ "&quot;": '"',
2063
+ "&#39;": "'",
2064
+ "&#x27;": "'",
2065
+ "&#x2F;": "/"
2066
+ };
2067
+ return s.replace(
2068
+ /&(?:amp|lt|gt|quot|#39|#x27|#x2F);/g,
2069
+ (entity) => htmlEntities[entity] || entity
2070
+ );
2071
+ }
2072
+ function escapeRegex(s) {
2073
+ return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
2074
+ }
2075
+ function slugify(s) {
2076
+ return s.toLowerCase().normalize("NFD").replace(/[\u0300-\u036f]/g, "").replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
2077
+ }
2078
+ function isValidIdentifier(s) {
2079
+ return /^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(s);
2080
+ }
2081
+ function isNumeric(s) {
2082
+ return !isNaN(parseFloat(s)) && isFinite(Number(s));
2083
+ }
2084
+ function isAlphanumeric(s) {
2085
+ return /^[a-zA-Z0-9]+$/.test(s);
2086
+ }
2087
+ function isAlpha(s) {
2088
+ return /^[a-zA-Z]+$/.test(s);
2089
+ }
2090
+ function randomString(length, charset = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789") {
2091
+ let result = "";
2092
+ for (let i = 0; i < length; i++) {
2093
+ result += charset[Math.floor(Math.random() * charset.length)];
2094
+ }
2095
+ return result;
2096
+ }
2097
+ function uuid() {
2098
+ return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, (c) => {
2099
+ const r = Math.random() * 16 | 0;
2100
+ const v = c === "x" ? r : r & 3 | 8;
2101
+ return v.toString(16);
2102
+ });
2103
+ }
2104
+ function indent(s, spaces, char = " ") {
2105
+ const prefix = char.repeat(spaces);
2106
+ return s.split("\n").map((line) => prefix + line).join("\n");
2107
+ }
2108
+ function dedent(s) {
2109
+ const linesList = lines(s);
2110
+ const nonEmptyLines = linesList.filter((l) => l.trim().length > 0);
2111
+ if (nonEmptyLines.length === 0) return s;
2112
+ const minIndent = Math.min(
2113
+ ...nonEmptyLines.map((line) => {
2114
+ const match = line.match(/^(\s*)/);
2115
+ return match ? match[1].length : 0;
2116
+ })
2117
+ );
2118
+ return linesList.map((line) => line.slice(minIndent)).join("\n");
2119
+ }
2120
+ function wordWrap(s, maxWidth) {
2121
+ const wordsList = words(s);
2122
+ const linesList = [];
2123
+ let currentLine = "";
2124
+ for (const word of wordsList) {
2125
+ if (currentLine.length === 0) {
2126
+ currentLine = word;
2127
+ } else if (currentLine.length + 1 + word.length <= maxWidth) {
2128
+ currentLine += " " + word;
2129
+ } else {
2130
+ linesList.push(currentLine);
2131
+ currentLine = word;
2132
+ }
2133
+ }
2134
+ if (currentLine.length > 0) {
2135
+ linesList.push(currentLine);
2136
+ }
2137
+ return linesList.join("\n");
2138
+ }
2139
+ function levenshtein(a, b) {
2140
+ if (a.length === 0) return b.length;
2141
+ if (b.length === 0) return a.length;
2142
+ const matrix = [];
2143
+ for (let i = 0; i <= b.length; i++) {
2144
+ matrix[i] = [i];
2145
+ }
2146
+ for (let j = 0; j <= a.length; j++) {
2147
+ matrix[0][j] = j;
2148
+ }
2149
+ for (let i = 1; i <= b.length; i++) {
2150
+ for (let j = 1; j <= a.length; j++) {
2151
+ if (b[i - 1] === a[j - 1]) {
2152
+ matrix[i][j] = matrix[i - 1][j - 1];
2153
+ } else {
2154
+ matrix[i][j] = Math.min(
2155
+ matrix[i - 1][j - 1] + 1,
2156
+ // substitution
2157
+ matrix[i][j - 1] + 1,
2158
+ // insertion
2159
+ matrix[i - 1][j] + 1
2160
+ // deletion
2161
+ );
2162
+ }
2163
+ }
2164
+ }
2165
+ return matrix[b.length][a.length];
2166
+ }
2167
+ function lcsLength(a, b) {
2168
+ const n = b.length;
2169
+ const dp = new Array(n + 1).fill(0);
2170
+ for (let i = 0; i < a.length; i++) {
2171
+ let prev = 0;
2172
+ for (let j = 0; j < n; j++) {
2173
+ const tmp = dp[j + 1];
2174
+ dp[j + 1] = a[i] === b[j] ? prev + 1 : Math.max(dp[j + 1], dp[j]);
2175
+ prev = tmp;
2176
+ }
2177
+ }
2178
+ return dp[n];
2179
+ }
2180
+ function similarity(a, b) {
2181
+ const total = a.length + b.length;
2182
+ if (total === 0) return 1;
2183
+ return 2 * lcsLength(a, b) / total;
2184
+ }
2185
+ function extractTraits(code) {
2186
+ const traits = /* @__PURE__ */ new Set();
2187
+ let m;
2188
+ const atRe = /@([a-zA-Z_]\w*)/g;
2189
+ while ((m = atRe.exec(code)) !== null) traits.add(`@${m[1]}`);
2190
+ const tagRe = /<([A-Z][a-zA-Z0-9]*)\b/g;
2191
+ while ((m = tagRe.exec(code)) !== null) traits.add(m[1]);
2192
+ return [...traits];
2193
+ }
2194
+
2195
+ // src/traits/EconomicPrimitives.ts
2196
+ function generateTxHash(from, to, price, timestamp) {
2197
+ let hash = 2166136261;
2198
+ const input = `${from}:${to}:${price}:${timestamp}`;
2199
+ for (let i = 0; i < input.length; i++) {
2200
+ hash ^= input.charCodeAt(i);
2201
+ hash = Math.imul(hash, 16777619);
2202
+ }
2203
+ return (hash >>> 0).toString(16).padStart(8, "0");
2204
+ }
2205
+ function executeTrade(record, buyer, price, timestamp) {
2206
+ if (record.locked) {
2207
+ return { ok: false, error: "TRANSFER_BLOCKED" };
2208
+ }
2209
+ if (price < 0) {
2210
+ return { ok: false, error: "INVALID_AMOUNT" };
2211
+ }
2212
+ const txHash = generateTxHash(record.owner, buyer, price, timestamp);
2213
+ const transfer = {
2214
+ from: record.owner,
2215
+ to: buyer,
2216
+ price,
2217
+ timestamp,
2218
+ txHash
2219
+ };
2220
+ const history = [transfer, ...record.history].slice(0, 50);
2221
+ return {
2222
+ ok: true,
2223
+ value: {
2224
+ owner: buyer,
2225
+ history,
2226
+ locked: false
2227
+ }
2228
+ };
2229
+ }
2230
+ var DEFAULT_DEPRECIATION = {
2231
+ decayRate: 1e-4,
2232
+ // 0.01% per second (~36% per hour)
2233
+ condition: 1,
2234
+ destroyThreshold: 0.01,
2235
+ repairable: true,
2236
+ repairCostMultiplier: 0.5
2237
+ };
2238
+ function calculateDepreciation(initialCondition, decayRate, elapsedSeconds) {
2239
+ if (decayRate <= 0) return initialCondition;
2240
+ if (elapsedSeconds <= 0) return initialCondition;
2241
+ return initialCondition * Math.exp(-decayRate * elapsedSeconds);
2242
+ }
2243
+ function depreciatedValue(baseValue, condition) {
2244
+ return baseValue * Math.max(0, Math.min(1, condition));
2245
+ }
2246
+ function isDestroyed(condition, threshold) {
2247
+ return condition <= threshold;
2248
+ }
2249
+ function calculateRepairCost(baseValue, currentCondition, repairCostMultiplier) {
2250
+ const conditionDeficit = 1 - Math.max(0, Math.min(1, currentCondition));
2251
+ return baseValue * conditionDeficit * repairCostMultiplier;
2252
+ }
2253
+ var DEFAULT_BONDING_CURVE = {
2254
+ curveType: "exponential",
2255
+ reserveRatio: 1,
2256
+ curveSteepness: 2,
2257
+ currentSupply: 0,
2258
+ reserveBalance: 0,
2259
+ transactionFee: 0.02,
2260
+ // 2% hard sink
2261
+ sigmoidK: 100,
2262
+ spatialDistanceFactor: 0
2263
+ };
2264
+ function bondingCurvePrice(supply, reserveRatio, curveSteepness, curveType = "exponential", sigmoidK = 100) {
2265
+ if (supply <= 0) return 0;
2266
+ if (reserveRatio <= 0) return 0;
2267
+ switch (curveType) {
2268
+ case "linear":
2269
+ return reserveRatio * supply;
2270
+ case "exponential":
2271
+ return reserveRatio * Math.pow(supply, 1 / curveSteepness);
2272
+ case "logarithmic":
2273
+ return reserveRatio * Math.log(supply + 1);
2274
+ case "sigmoid": {
2275
+ const sn = Math.pow(supply, curveSteepness);
2276
+ const kn = Math.pow(sigmoidK, curveSteepness);
2277
+ return reserveRatio * (sn / (kn + sn));
2278
+ }
2279
+ default:
2280
+ return reserveRatio * Math.pow(supply, 1 / curveSteepness);
2281
+ }
2282
+ }
2283
+ function bondingCurveBuyCost(config, amount) {
2284
+ if (amount <= 0) return 0;
2285
+ const n = Math.max(10, Math.ceil(amount));
2286
+ const h = amount / n;
2287
+ let sum = 0;
2288
+ const s0 = config.currentSupply;
2289
+ for (let i = 0; i <= n; i++) {
2290
+ const s = s0 + i * h;
2291
+ const p = bondingCurvePrice(
2292
+ s,
2293
+ config.reserveRatio,
2294
+ config.curveSteepness,
2295
+ config.curveType,
2296
+ config.sigmoidK
2297
+ );
2298
+ if (i === 0 || i === n) {
2299
+ sum += p;
2300
+ } else if (i % 2 === 1) {
2301
+ sum += 4 * p;
2302
+ } else {
2303
+ sum += 2 * p;
2304
+ }
2305
+ }
2306
+ const cost = h / 3 * sum;
2307
+ return cost * (1 + config.transactionFee);
2308
+ }
2309
+ function bondingCurveSellRefund(config, amount) {
2310
+ if (amount <= 0) return 0;
2311
+ if (amount > config.currentSupply) return 0;
2312
+ const n = Math.max(10, Math.ceil(amount));
2313
+ const h = amount / n;
2314
+ let sum = 0;
2315
+ const s0 = config.currentSupply - amount;
2316
+ for (let i = 0; i <= n; i++) {
2317
+ const s = s0 + i * h;
2318
+ const p = bondingCurvePrice(
2319
+ s,
2320
+ config.reserveRatio,
2321
+ config.curveSteepness,
2322
+ config.curveType,
2323
+ config.sigmoidK
2324
+ );
2325
+ if (i === 0 || i === n) {
2326
+ sum += p;
2327
+ } else if (i % 2 === 1) {
2328
+ sum += 4 * p;
2329
+ } else {
2330
+ sum += 2 * p;
2331
+ }
2332
+ }
2333
+ const refund = h / 3 * sum;
2334
+ return refund * (1 - config.transactionFee);
2335
+ }
2336
+ function spatialPrice(basePrice, distanceToHub, distanceFactor) {
2337
+ if (distanceFactor <= 0 || distanceToHub <= 0) return basePrice;
2338
+ return basePrice * (1 + distanceFactor * distanceToHub);
2339
+ }
2340
+ var DEFAULT_WEALTH_TAX = {
2341
+ threshold: 1e4,
2342
+ baseRate: 0.01,
2343
+ // 1% base
2344
+ maxEffectiveRate: 0.05,
2345
+ // 5% cap
2346
+ collectionInterval: "daily",
2347
+ enableRedistribution: true,
2348
+ redistributionFraction: 0.7
2349
+ // 70% redistributed, 30% burned as hard sink
2350
+ };
2351
+ function calculateTaxRate(wealth, threshold, baseRate, maxEffectiveRate) {
2352
+ if (wealth <= threshold) return 0;
2353
+ if (threshold <= 0) return 0;
2354
+ const rate = Math.log(wealth / threshold) * baseRate;
2355
+ return Math.min(rate, maxEffectiveRate);
2356
+ }
2357
+ function calculateTaxAmount(wealth, config) {
2358
+ const rate = calculateTaxRate(wealth, config.threshold, config.baseRate, config.maxEffectiveRate);
2359
+ return wealth * rate;
2360
+ }
2361
+ function calculateRedistribution(totalTaxCollected, recipientCount, redistributionFraction) {
2362
+ if (recipientCount <= 0 || totalTaxCollected <= 0) {
2363
+ return { perRecipient: 0, burned: totalTaxCollected };
2364
+ }
2365
+ const redistributed = totalTaxCollected * redistributionFraction;
2366
+ const burned = totalTaxCollected - redistributed;
2367
+ const perRecipient = redistributed / recipientCount;
2368
+ return { perRecipient, burned };
2369
+ }
2370
+ var DEFAULT_PID = {
2371
+ kp: 0.5,
2372
+ ki: 0.01,
2373
+ kd: 0.1,
2374
+ setpoint: 0,
2375
+ outputMin: -1,
2376
+ outputMax: 1,
2377
+ integralLimit: 10
2378
+ };
2379
+ function createPIDState() {
2380
+ return {
2381
+ previousError: 0,
2382
+ integral: 0,
2383
+ lastOutput: 0,
2384
+ initialized: false
2385
+ };
2386
+ }
2387
+ function updatePID(config, state, measurement, dt) {
2388
+ if (dt <= 0) return state.lastOutput;
2389
+ const error = config.setpoint - measurement;
2390
+ const p = config.kp * error;
2391
+ state.integral += error * dt;
2392
+ state.integral = Math.max(-config.integralLimit, Math.min(config.integralLimit, state.integral));
2393
+ const i = config.ki * state.integral;
2394
+ let d = 0;
2395
+ if (state.initialized) {
2396
+ d = config.kd * ((error - state.previousError) / dt);
2397
+ }
2398
+ let output = p + i + d;
2399
+ output = Math.max(config.outputMin, Math.min(config.outputMax, output));
2400
+ state.previousError = error;
2401
+ state.lastOutput = output;
2402
+ state.initialized = true;
2403
+ return output;
2404
+ }
2405
+ function createDualLoopPIDState() {
2406
+ return {
2407
+ innerState: createPIDState(),
2408
+ outerState: createPIDState(),
2409
+ faucetMultiplier: 1
2410
+ };
2411
+ }
2412
+ function updateDualLoopPID(config, state, totalMoneySupply, currentFaucetRate, dt) {
2413
+ const targetSupply = config.perCapitaTarget * config.activePlayerCount;
2414
+ const outerConfig = { ...config.outerLoop, setpoint: targetSupply };
2415
+ const outerOutput = updatePID(outerConfig, state.outerState, totalMoneySupply, dt);
2416
+ const desiredFaucetRate = currentFaucetRate * (1 + outerOutput * 0.1);
2417
+ const innerConfig = { ...config.innerLoop, setpoint: desiredFaucetRate };
2418
+ const innerOutput = updatePID(innerConfig, state.innerState, currentFaucetRate, dt);
2419
+ state.faucetMultiplier = Math.max(0, Math.min(2, 1 + innerOutput));
2420
+ return state.faucetMultiplier;
2421
+ }
2422
+ function createFaucetSinkMetrics(timestamp) {
2423
+ return {
2424
+ totalFaucet: 0,
2425
+ totalSink: 0,
2426
+ ratio: 1,
2427
+ velocity: 0,
2428
+ periodStart: timestamp,
2429
+ ratioHistory: []
2430
+ };
2431
+ }
2432
+ function recordFaucet(metrics, amount) {
2433
+ metrics.totalFaucet += amount;
2434
+ metrics.ratio = metrics.totalSink > 0 ? metrics.totalFaucet / metrics.totalSink : metrics.totalFaucet > 0 ? Infinity : 1;
2435
+ }
2436
+ function recordSink(metrics, amount) {
2437
+ metrics.totalSink += amount;
2438
+ metrics.ratio = metrics.totalSink > 0 ? metrics.totalFaucet / metrics.totalSink : metrics.totalFaucet > 0 ? Infinity : 1;
2439
+ }
2440
+ function resetMetricsPeriod(metrics, timestamp) {
2441
+ if (metrics.totalFaucet > 0 || metrics.totalSink > 0) {
2442
+ metrics.ratioHistory.push(metrics.ratio);
2443
+ if (metrics.ratioHistory.length > 100) {
2444
+ metrics.ratioHistory.shift();
2445
+ }
2446
+ }
2447
+ metrics.totalFaucet = 0;
2448
+ metrics.totalSink = 0;
2449
+ metrics.ratio = 1;
2450
+ metrics.velocity = 0;
2451
+ metrics.periodStart = timestamp;
2452
+ }
2453
+
2454
+ // src/traits/EconomicTraits.ts
2455
+ var EconomicTraits = {
2456
+ // ---------------------------------------------------------------------------
2457
+ // 1. TRADEABLE
2458
+ // ---------------------------------------------------------------------------
2459
+ tradeable: {
2460
+ name: "@tradeable",
2461
+ description: "Makes a composition or node transferable between agents. Tracks ownership history with transaction hashes for integrity verification (P.030.04). Supports lock/unlock for escrow patterns and auction integration.",
2462
+ params: {
2463
+ initial_owner: {
2464
+ type: "AgentID",
2465
+ required: true,
2466
+ description: "The agent who initially owns this entity."
2467
+ },
2468
+ transferable: {
2469
+ type: "boolean",
2470
+ required: false,
2471
+ default: true,
2472
+ description: "Whether transfers are currently allowed."
2473
+ },
2474
+ min_price: {
2475
+ type: "number",
2476
+ required: false,
2477
+ default: 0,
2478
+ description: "Minimum trade price (prevents value manipulation)."
2479
+ },
2480
+ max_history: {
2481
+ type: "number",
2482
+ required: false,
2483
+ default: 50,
2484
+ description: "Maximum ownership history entries retained."
2485
+ },
2486
+ requires_presence: {
2487
+ type: "boolean",
2488
+ required: false,
2489
+ default: false,
2490
+ description: "VR-specific: require spatial co-location for trade (anti-exploit, Layer 7)."
2491
+ },
2492
+ presence_radius: {
2493
+ type: "number",
2494
+ required: false,
2495
+ default: 5,
2496
+ description: "Maximum distance in meters for presence-based trades."
2497
+ }
2498
+ },
2499
+ validator: (params) => {
2500
+ if (!params.initial_owner || typeof params.initial_owner !== "string") return false;
2501
+ if (params.min_price !== void 0 && params.min_price < 0) return false;
2502
+ return true;
2503
+ },
2504
+ requiredPermissions: ["economy.trade"],
2505
+ economicLayer: 0,
2506
+ // Layer 0: Integrity
2507
+ composesWith: ["@depreciating", "@bonding_curved", "@taxable_wealth"],
2508
+ compiler_hints: {
2509
+ requires_runtime: ["EconomicRuntime.executeTrade", "EconomicRuntime.verifyOwnership"],
2510
+ thread_safety: "any"
2511
+ }
2512
+ },
2513
+ // ---------------------------------------------------------------------------
2514
+ // 2. DEPRECIATING
2515
+ // ---------------------------------------------------------------------------
2516
+ depreciating: {
2517
+ name: "@depreciating",
2518
+ description: "Applies time-based value decay to an entity (hard sink mechanic). Uses exponential decay: condition(t) = condition(0) * e^(-rate * t). When condition reaches destroy_threshold, the entity is consumed -- removing currency/value from circulation permanently (W.031).",
2519
+ params: {
2520
+ decay_rate: {
2521
+ type: "number",
2522
+ required: true,
2523
+ description: "Per-second decay rate (0.0 - 1.0). E.g., 0.001 = 0.1% per second."
2524
+ },
2525
+ initial_condition: {
2526
+ type: "number",
2527
+ required: false,
2528
+ default: 1,
2529
+ description: "Starting condition (1.0 = mint, 0.0 = destroyed)."
2530
+ },
2531
+ destroy_threshold: {
2532
+ type: "number",
2533
+ required: false,
2534
+ default: 0.01,
2535
+ description: "Condition level at which the entity is destroyed."
2536
+ },
2537
+ repairable: {
2538
+ type: "boolean",
2539
+ required: false,
2540
+ default: true,
2541
+ description: "Whether the entity can be repaired to restore condition."
2542
+ },
2543
+ repair_cost_multiplier: {
2544
+ type: "number",
2545
+ required: false,
2546
+ default: 0.5,
2547
+ description: "Repair cost as a fraction of base value per unit condition."
2548
+ },
2549
+ emit_on_destroy: {
2550
+ type: "string",
2551
+ required: false,
2552
+ default: "on_entity_destroyed",
2553
+ description: "Event emitted when condition reaches destroy threshold."
2554
+ }
2555
+ },
2556
+ validator: (params) => {
2557
+ if (params.decay_rate === void 0 || params.decay_rate < 0 || params.decay_rate > 1)
2558
+ return false;
2559
+ if (params.initial_condition !== void 0 && (params.initial_condition < 0 || params.initial_condition > 1))
2560
+ return false;
2561
+ if (params.destroy_threshold !== void 0 && (params.destroy_threshold < 0 || params.destroy_threshold > 1))
2562
+ return false;
2563
+ return true;
2564
+ },
2565
+ requiredPermissions: ["economy.burn"],
2566
+ economicLayer: 1,
2567
+ // Layer 1: Flow Control (sink side)
2568
+ composesWith: ["@tradeable", "@bonding_curved"],
2569
+ compiler_hints: {
2570
+ requires_runtime: ["EconomicRuntime.updateDepreciation", "EconomicRuntime.destroyEntity"],
2571
+ thread_safety: "worker_thread",
2572
+ performance_budget_ms: 0.1
2573
+ // Must be fast -- called every tick
2574
+ }
2575
+ },
2576
+ // ---------------------------------------------------------------------------
2577
+ // 3. BONDING_CURVED
2578
+ // ---------------------------------------------------------------------------
2579
+ bonding_curved: {
2580
+ name: "@bonding_curved",
2581
+ description: "Attaches a bonding curve to a marketplace or item category for autonomous price discovery. Price is determined by P = f(supply) where f depends on curve_type. Provides continuous liquidity via reserve pool without order books (W.035, P.030.02). Supports spatial pricing for VR trade geography.",
2582
+ params: {
2583
+ curve_type: {
2584
+ type: "string",
2585
+ required: false,
2586
+ default: "exponential",
2587
+ description: "Curve shape: linear | exponential | logarithmic | sigmoid.",
2588
+ validation: (val) => ["linear", "exponential", "logarithmic", "sigmoid"].includes(val)
2589
+ },
2590
+ reserve_ratio: {
2591
+ type: "number",
2592
+ required: true,
2593
+ description: "Base price multiplier (R in the price formula)."
2594
+ },
2595
+ curve_steepness: {
2596
+ type: "number",
2597
+ required: false,
2598
+ default: 2,
2599
+ description: "Controls price sensitivity to supply changes (n in P = R * S^(1/n))."
2600
+ },
2601
+ transaction_fee: {
2602
+ type: "number",
2603
+ required: false,
2604
+ default: 0.02,
2605
+ description: "Fee percentage per transaction (hard sink). Range: 0.0 - 0.5."
2606
+ },
2607
+ initial_supply: {
2608
+ type: "number",
2609
+ required: false,
2610
+ default: 0,
2611
+ description: "Initial token/item supply on the curve."
2612
+ },
2613
+ initial_reserve: {
2614
+ type: "number",
2615
+ required: false,
2616
+ default: 0,
2617
+ description: "Initial reserve pool balance backing the curve."
2618
+ },
2619
+ sigmoid_k: {
2620
+ type: "number",
2621
+ required: false,
2622
+ default: 100,
2623
+ description: "Half-saturation constant for sigmoid curves."
2624
+ },
2625
+ spatial_distance_factor: {
2626
+ type: "number",
2627
+ required: false,
2628
+ default: 0,
2629
+ description: "VR spatial pricing: price multiplier per unit distance from hub. 0.0 = no spatial effect. Creates emergent trade routes (P.030.02 ENRICHED)."
2630
+ }
2631
+ },
2632
+ validator: (params) => {
2633
+ if (params.reserve_ratio === void 0 || params.reserve_ratio <= 0) return false;
2634
+ if (params.curve_steepness !== void 0 && params.curve_steepness <= 0) return false;
2635
+ if (params.transaction_fee !== void 0 && (params.transaction_fee < 0 || params.transaction_fee > 0.5))
2636
+ return false;
2637
+ if (params.curve_type !== void 0) {
2638
+ if (!["linear", "exponential", "logarithmic", "sigmoid"].includes(params.curve_type))
2639
+ return false;
2640
+ }
2641
+ return true;
2642
+ },
2643
+ requiredPermissions: ["economy.set_price", "economy.trade"],
2644
+ economicLayer: 2,
2645
+ // Layer 2: Price Discovery
2646
+ composesWith: ["@tradeable", "@depreciating", "@pid_controlled"],
2647
+ compiler_hints: {
2648
+ requires_runtime: [
2649
+ "EconomicRuntime.bondingCurveBuy",
2650
+ "EconomicRuntime.bondingCurveSell",
2651
+ "EconomicRuntime.getSpotPrice"
2652
+ ],
2653
+ thread_safety: "any",
2654
+ performance_budget_ms: 1
2655
+ }
2656
+ },
2657
+ // ---------------------------------------------------------------------------
2658
+ // 4. TAXABLE_WEALTH
2659
+ // ---------------------------------------------------------------------------
2660
+ taxable_wealth: {
2661
+ name: "@taxable_wealth",
2662
+ description: "Applies progressive logarithmic wealth taxation with optional redistribution to the lowest-wealth quintile (P.030.03, W.034). Tax = 0 below threshold, then rate = min(max_rate, log(wealth/threshold) * base_rate). Collected taxes are partially redistributed (UBI) and partially burned (hard sink).",
2663
+ params: {
2664
+ threshold: {
2665
+ type: "number",
2666
+ required: true,
2667
+ description: "Wealth level below which no tax is levied."
2668
+ },
2669
+ base_rate: {
2670
+ type: "number",
2671
+ required: false,
2672
+ default: 0.01,
2673
+ description: "Base tax rate multiplied by log(wealth/threshold). Range: 0.0 - 0.1."
2674
+ },
2675
+ max_effective_rate: {
2676
+ type: "number",
2677
+ required: false,
2678
+ default: 0.05,
2679
+ description: "Maximum effective tax rate cap (prevents punishing engagement)."
2680
+ },
2681
+ collection_interval: {
2682
+ type: "string",
2683
+ required: false,
2684
+ default: "daily",
2685
+ description: "How often taxes are collected: hourly | daily | weekly.",
2686
+ validation: (val) => ["hourly", "daily", "weekly"].includes(val)
2687
+ },
2688
+ enable_redistribution: {
2689
+ type: "boolean",
2690
+ required: false,
2691
+ default: true,
2692
+ description: "Whether collected tax is redistributed to lowest-wealth players."
2693
+ },
2694
+ redistribution_fraction: {
2695
+ type: "number",
2696
+ required: false,
2697
+ default: 0.7,
2698
+ description: "Fraction of tax redistributed (remainder burned as hard sink). Range: 0.0 - 1.0."
2699
+ },
2700
+ emit_on_collection: {
2701
+ type: "string",
2702
+ required: false,
2703
+ default: "on_tax_collected",
2704
+ description: "Event emitted when taxes are collected."
2705
+ },
2706
+ public_ledger: {
2707
+ type: "boolean",
2708
+ required: false,
2709
+ default: true,
2710
+ description: "Whether tax collections and redistribution are visible in the economy dashboard (Layer 6: Transparency, W.038)."
2711
+ }
2712
+ },
2713
+ validator: (params) => {
2714
+ if (params.threshold === void 0 || params.threshold < 0) return false;
2715
+ if (params.base_rate !== void 0 && (params.base_rate < 0 || params.base_rate > 0.1))
2716
+ return false;
2717
+ if (params.max_effective_rate !== void 0 && (params.max_effective_rate < 0 || params.max_effective_rate > 1))
2718
+ return false;
2719
+ if (params.redistribution_fraction !== void 0 && (params.redistribution_fraction < 0 || params.redistribution_fraction > 1))
2720
+ return false;
2721
+ return true;
2722
+ },
2723
+ requiredPermissions: ["economy.tax", "economy.redistribute"],
2724
+ economicLayer: 4,
2725
+ // Layer 4: Redistribution
2726
+ composesWith: ["@tradeable", "@pid_controlled"],
2727
+ compiler_hints: {
2728
+ requires_runtime: [
2729
+ "EconomicRuntime.collectTax",
2730
+ "EconomicRuntime.redistribute",
2731
+ "EconomicRuntime.getGiniCoefficient"
2732
+ ],
2733
+ thread_safety: "worker_thread",
2734
+ performance_budget_ms: 5
2735
+ // Runs on collection interval, not per-frame
2736
+ }
2737
+ },
2738
+ // ---------------------------------------------------------------------------
2739
+ // 5. PID_CONTROLLED
2740
+ // ---------------------------------------------------------------------------
2741
+ pid_controlled: {
2742
+ name: "@pid_controlled",
2743
+ description: "Attaches a dual-loop PID feedback controller to regulate economic flow (P.030.01, W.032). Inner loop adjusts per-source faucet rates (fast). Outer loop adjusts inner setpoint based on total money supply (slow). Achieves <10% currency variance long-term while preserving gameplay variance.",
2744
+ params: {
2745
+ target_per_capita: {
2746
+ type: "number",
2747
+ required: true,
2748
+ description: "Target currency per active player (outer loop setpoint)."
2749
+ },
2750
+ inner_kp: {
2751
+ type: "number",
2752
+ required: false,
2753
+ default: 0.5,
2754
+ description: "Inner loop proportional gain."
2755
+ },
2756
+ inner_ki: {
2757
+ type: "number",
2758
+ required: false,
2759
+ default: 0.01,
2760
+ description: "Inner loop integral gain."
2761
+ },
2762
+ inner_kd: {
2763
+ type: "number",
2764
+ required: false,
2765
+ default: 0.1,
2766
+ description: "Inner loop derivative gain."
2767
+ },
2768
+ outer_kp: {
2769
+ type: "number",
2770
+ required: false,
2771
+ default: 0.3,
2772
+ description: "Outer loop proportional gain."
2773
+ },
2774
+ outer_ki: {
2775
+ type: "number",
2776
+ required: false,
2777
+ default: 5e-3,
2778
+ description: "Outer loop integral gain."
2779
+ },
2780
+ outer_kd: {
2781
+ type: "number",
2782
+ required: false,
2783
+ default: 0.05,
2784
+ description: "Outer loop derivative gain."
2785
+ },
2786
+ update_interval: {
2787
+ type: "number",
2788
+ required: false,
2789
+ default: 1,
2790
+ description: "Controller update interval in seconds."
2791
+ },
2792
+ faucet_min_multiplier: {
2793
+ type: "number",
2794
+ required: false,
2795
+ default: 0.1,
2796
+ description: "Minimum faucet rate multiplier (never fully stop rewards)."
2797
+ },
2798
+ faucet_max_multiplier: {
2799
+ type: "number",
2800
+ required: false,
2801
+ default: 2,
2802
+ description: "Maximum faucet rate multiplier."
2803
+ },
2804
+ track_faucet_sink_ratio: {
2805
+ type: "boolean",
2806
+ required: false,
2807
+ default: true,
2808
+ description: "Whether to track and emit faucet/sink ratio metrics (W.031)."
2809
+ },
2810
+ emit_on_adjustment: {
2811
+ type: "string",
2812
+ required: false,
2813
+ default: "on_faucet_adjusted",
2814
+ description: "Event emitted when faucet rate is adjusted."
2815
+ }
2816
+ },
2817
+ validator: (params) => {
2818
+ if (params.target_per_capita === void 0 || params.target_per_capita <= 0) return false;
2819
+ const gains = [
2820
+ params.inner_kp,
2821
+ params.inner_ki,
2822
+ params.inner_kd,
2823
+ params.outer_kp,
2824
+ params.outer_ki,
2825
+ params.outer_kd
2826
+ ];
2827
+ for (const g of gains) {
2828
+ if (g !== void 0 && (typeof g !== "number" || isNaN(g))) return false;
2829
+ }
2830
+ if (params.update_interval !== void 0 && params.update_interval <= 0) return false;
2831
+ return true;
2832
+ },
2833
+ requiredPermissions: ["economy.tune_pid", "economy.mint", "economy.burn"],
2834
+ economicLayer: 1,
2835
+ // Layer 1: Flow Control
2836
+ composesWith: ["@bonding_curved", "@taxable_wealth"],
2837
+ compiler_hints: {
2838
+ requires_runtime: [
2839
+ "EconomicRuntime.updatePID",
2840
+ "EconomicRuntime.getFaucetMultiplier",
2841
+ "EconomicRuntime.getFaucetSinkMetrics"
2842
+ ],
2843
+ thread_safety: "worker_thread",
2844
+ performance_budget_ms: 0.5
2845
+ }
2846
+ }
2847
+ };
2848
+ function getEconomicTraitNames() {
2849
+ return Object.keys(EconomicTraits).map((k) => EconomicTraits[k].name);
2850
+ }
2851
+ function getEconomicTrait(name) {
2852
+ const key = name.startsWith("@") ? name.slice(1) : name;
2853
+ return EconomicTraits[key];
2854
+ }
2855
+ function validateTraitComposition(traitNames) {
2856
+ for (const name of traitNames) {
2857
+ const trait = getEconomicTrait(name);
2858
+ if (!trait) {
2859
+ return `Unknown economic trait: ${name}`;
2860
+ }
2861
+ }
2862
+ for (const name of traitNames) {
2863
+ const trait = getEconomicTrait(name);
2864
+ for (const other of traitNames) {
2865
+ if (other === name) continue;
2866
+ const otherPrefixed = other.startsWith("@") ? other : `@${other}`;
2867
+ if (!trait.composesWith.includes(otherPrefixed)) {
2868
+ return `Trait ${trait.name} does not compose with ${otherPrefixed}`;
2869
+ }
2870
+ }
2871
+ }
2872
+ return null;
2873
+ }
2874
+ function getRequiredPermissions(traitNames) {
2875
+ const permissions = /* @__PURE__ */ new Set();
2876
+ for (const name of traitNames) {
2877
+ const trait = getEconomicTrait(name);
2878
+ if (trait) {
2879
+ for (const perm2 of trait.requiredPermissions) {
2880
+ permissions.add(perm2);
2881
+ }
2882
+ }
2883
+ }
2884
+ return Array.from(permissions).sort();
2885
+ }
2886
+
2887
+ // src/traits/SimulationLabPrimitives.ts
2888
+ function isParameterRange(sweep) {
2889
+ return "min" in sweep && "max" in sweep && "step" in sweep;
2890
+ }
2891
+ function expandSweep(sweep) {
2892
+ if (!isParameterRange(sweep)) {
2893
+ return sweep.values.slice();
2894
+ }
2895
+ const range = sweep;
2896
+ if (range.step <= 0) return [range.min];
2897
+ if (range.min > range.max) return [];
2898
+ const values = [];
2899
+ for (let v = range.min; v <= range.max + range.step * 1e-3; v += range.step) {
2900
+ values.push(Math.round(v * 1e10) / 1e10);
2901
+ }
2902
+ return values;
2903
+ }
2904
+ function generateSweepCombinations(sweeps) {
2905
+ if (sweeps.length === 0) return [{}];
2906
+ const expanded = sweeps.map((s) => ({
2907
+ name: s.name,
2908
+ values: expandSweep(s)
2909
+ }));
2910
+ let combinations = [{}];
2911
+ for (const { name, values } of expanded) {
2912
+ const newCombinations = [];
2913
+ for (const combo of combinations) {
2914
+ for (const val of values) {
2915
+ newCombinations.push({ ...combo, [name]: val });
2916
+ }
2917
+ }
2918
+ combinations = newCombinations;
2919
+ }
2920
+ return combinations;
2921
+ }
2922
+ function mean(data) {
2923
+ if (data.length === 0) return 0;
2924
+ return data.reduce((sum, v) => sum + v, 0) / data.length;
2925
+ }
2926
+ function variance(data) {
2927
+ if (data.length < 2) return 0;
2928
+ const m = mean(data);
2929
+ const squaredDiffs = data.reduce((sum, v) => sum + (v - m) ** 2, 0);
2930
+ return squaredDiffs / (data.length - 1);
2931
+ }
2932
+ function standardDeviation(data) {
2933
+ return Math.sqrt(variance(data));
2934
+ }
2935
+ function standardError(data) {
2936
+ if (data.length === 0) return 0;
2937
+ return standardDeviation(data) / Math.sqrt(data.length);
2938
+ }
2939
+ function cohensD(group1, group2) {
2940
+ if (group1.length < 2 || group2.length < 2) return 0;
2941
+ const m1 = mean(group1);
2942
+ const m2 = mean(group2);
2943
+ const v1 = variance(group1);
2944
+ const v2 = variance(group2);
2945
+ const n1 = group1.length;
2946
+ const n2 = group2.length;
2947
+ const pooledVar = ((n1 - 1) * v1 + (n2 - 1) * v2) / (n1 + n2 - 2);
2948
+ const pooledStd = Math.sqrt(pooledVar);
2949
+ if (pooledStd === 0) return 0;
2950
+ return (m1 - m2) / pooledStd;
2951
+ }
2952
+ function tTest(group1, group2, alpha = 0.05, direction = "different") {
2953
+ const n1 = group1.length;
2954
+ const n2 = group2.length;
2955
+ if (n1 < 2 || n2 < 2) {
2956
+ return {
2957
+ statistic: 0,
2958
+ pValue: 1,
2959
+ significant: false,
2960
+ confidenceInterval: [0, 0],
2961
+ effectSize: 0,
2962
+ testName: "welch_t_test",
2963
+ sampleSize: n1 + n2
2964
+ };
2965
+ }
2966
+ const m1 = mean(group1);
2967
+ const m2 = mean(group2);
2968
+ const v1 = variance(group1);
2969
+ const v2 = variance(group2);
2970
+ const se = Math.sqrt(v1 / n1 + v2 / n2);
2971
+ if (se === 0) {
2972
+ return {
2973
+ statistic: 0,
2974
+ pValue: m1 === m2 ? 1 : 0,
2975
+ significant: m1 !== m2,
2976
+ confidenceInterval: [m1 - m2, m1 - m2],
2977
+ effectSize: 0,
2978
+ testName: "welch_t_test",
2979
+ sampleSize: n1 + n2
2980
+ };
2981
+ }
2982
+ const t = (m1 - m2) / se;
2983
+ const num = (v1 / n1 + v2 / n2) ** 2;
2984
+ const den = (v1 / n1) ** 2 / (n1 - 1) + (v2 / n2) ** 2 / (n2 - 1);
2985
+ const df = num / den;
2986
+ const pTwoTailed = tDistPValue(Math.abs(t), df);
2987
+ let pValue;
2988
+ switch (direction) {
2989
+ case "greater":
2990
+ pValue = t > 0 ? pTwoTailed / 2 : 1 - pTwoTailed / 2;
2991
+ break;
2992
+ case "less":
2993
+ pValue = t < 0 ? pTwoTailed / 2 : 1 - pTwoTailed / 2;
2994
+ break;
2995
+ case "equal":
2996
+ pValue = 1 - pTwoTailed;
2997
+ break;
2998
+ default:
2999
+ pValue = pTwoTailed;
3000
+ }
3001
+ const tCrit = tDistCritical(alpha, df);
3002
+ const diff = m1 - m2;
3003
+ const ci = [diff - tCrit * se, diff + tCrit * se];
3004
+ return {
3005
+ statistic: t,
3006
+ pValue,
3007
+ significant: pValue < alpha,
3008
+ confidenceInterval: ci,
3009
+ effectSize: cohensD(group1, group2),
3010
+ testName: "welch_t_test",
3011
+ sampleSize: n1 + n2
3012
+ };
3013
+ }
3014
+ function oneSampleTTest(data, populationMean, alpha = 0.05, direction = "different") {
3015
+ const n = data.length;
3016
+ if (n < 2) {
3017
+ return {
3018
+ statistic: 0,
3019
+ pValue: 1,
3020
+ significant: false,
3021
+ confidenceInterval: [0, 0],
3022
+ effectSize: 0,
3023
+ testName: "one_sample_t_test",
3024
+ sampleSize: n
3025
+ };
3026
+ }
3027
+ const m = mean(data);
3028
+ const se = standardError(data);
3029
+ if (se === 0) {
3030
+ return {
3031
+ statistic: 0,
3032
+ pValue: m === populationMean ? 1 : 0,
3033
+ significant: m !== populationMean,
3034
+ confidenceInterval: [m, m],
3035
+ effectSize: 0,
3036
+ testName: "one_sample_t_test",
3037
+ sampleSize: n
3038
+ };
3039
+ }
3040
+ const t = (m - populationMean) / se;
3041
+ const df = n - 1;
3042
+ const pTwoTailed = tDistPValue(Math.abs(t), df);
3043
+ let pValue;
3044
+ switch (direction) {
3045
+ case "greater":
3046
+ pValue = t > 0 ? pTwoTailed / 2 : 1 - pTwoTailed / 2;
3047
+ break;
3048
+ case "less":
3049
+ pValue = t < 0 ? pTwoTailed / 2 : 1 - pTwoTailed / 2;
3050
+ break;
3051
+ default:
3052
+ pValue = pTwoTailed;
3053
+ }
3054
+ const tCrit = tDistCritical(alpha, df);
3055
+ const ci = [m - tCrit * se, m + tCrit * se];
3056
+ const sd = standardDeviation(data);
3057
+ const effectSize = sd > 0 ? (m - populationMean) / sd : 0;
3058
+ return {
3059
+ statistic: t,
3060
+ pValue,
3061
+ significant: pValue < alpha,
3062
+ confidenceInterval: ci,
3063
+ effectSize,
3064
+ testName: "one_sample_t_test",
3065
+ sampleSize: n
3066
+ };
3067
+ }
3068
+ function mannWhitneyU(group1, group2, alpha = 0.05) {
3069
+ const n1 = group1.length;
3070
+ const n2 = group2.length;
3071
+ if (n1 === 0 || n2 === 0) {
3072
+ return {
3073
+ statistic: 0,
3074
+ pValue: 1,
3075
+ significant: false,
3076
+ confidenceInterval: [0, 0],
3077
+ effectSize: 0,
3078
+ testName: "mann_whitney_u",
3079
+ sampleSize: n1 + n2
3080
+ };
3081
+ }
3082
+ let u1 = 0;
3083
+ for (const a of group1) {
3084
+ for (const b of group2) {
3085
+ if (a > b) u1++;
3086
+ else if (a === b) u1 += 0.5;
3087
+ }
3088
+ }
3089
+ const u2 = n1 * n2 - u1;
3090
+ const u = Math.min(u1, u2);
3091
+ const meanU = n1 * n2 / 2;
3092
+ const sigmaU = Math.sqrt(n1 * n2 * (n1 + n2 + 1) / 12);
3093
+ if (sigmaU === 0) {
3094
+ return {
3095
+ statistic: u,
3096
+ pValue: 1,
3097
+ significant: false,
3098
+ confidenceInterval: [0, 0],
3099
+ effectSize: 0,
3100
+ testName: "mann_whitney_u",
3101
+ sampleSize: n1 + n2
3102
+ };
3103
+ }
3104
+ const z = (u - meanU) / sigmaU;
3105
+ const pValue = 2 * normalCDF(-Math.abs(z));
3106
+ const effectSize = 1 - 2 * u / (n1 * n2);
3107
+ return {
3108
+ statistic: u,
3109
+ pValue,
3110
+ significant: pValue < alpha,
3111
+ confidenceInterval: [0, 0],
3112
+ // CI not standard for U-test
3113
+ effectSize,
3114
+ testName: "mann_whitney_u",
3115
+ sampleSize: n1 + n2
3116
+ };
3117
+ }
3118
+ function chiSquaredTest(observed, expected, alpha = 0.05) {
3119
+ if (observed.length !== expected.length || observed.length === 0) {
3120
+ return {
3121
+ statistic: 0,
3122
+ pValue: 1,
3123
+ significant: false,
3124
+ confidenceInterval: [0, 0],
3125
+ effectSize: 0,
3126
+ testName: "chi_squared",
3127
+ sampleSize: 0
3128
+ };
3129
+ }
3130
+ let chiSq = 0;
3131
+ let totalObserved = 0;
3132
+ for (let i = 0; i < observed.length; i++) {
3133
+ if (expected[i] <= 0) continue;
3134
+ chiSq += (observed[i] - expected[i]) ** 2 / expected[i];
3135
+ totalObserved += observed[i];
3136
+ }
3137
+ const df = observed.length - 1;
3138
+ if (df <= 0) {
3139
+ return {
3140
+ statistic: chiSq,
3141
+ pValue: 1,
3142
+ significant: false,
3143
+ confidenceInterval: [0, 0],
3144
+ effectSize: 0,
3145
+ testName: "chi_squared",
3146
+ sampleSize: totalObserved
3147
+ };
3148
+ }
3149
+ const pValue = chiSquaredPValue(chiSq, df);
3150
+ const k = observed.length;
3151
+ const effectSize = totalObserved > 0 ? Math.sqrt(chiSq / (totalObserved * (k - 1))) : 0;
3152
+ return {
3153
+ statistic: chiSq,
3154
+ pValue,
3155
+ significant: pValue < alpha,
3156
+ confidenceInterval: [0, 0],
3157
+ effectSize,
3158
+ testName: "chi_squared",
3159
+ sampleSize: totalObserved
3160
+ };
3161
+ }
3162
+ function extractMetric(results, metricName) {
3163
+ return results.filter((r) => metricName in r.values).map((r) => r.values[metricName]);
3164
+ }
3165
+ function groupByParameter(results, paramName) {
3166
+ const groups = /* @__PURE__ */ new Map();
3167
+ for (const r of results) {
3168
+ const val = r.params[paramName];
3169
+ if (val === void 0) continue;
3170
+ if (!groups.has(val)) groups.set(val, []);
3171
+ groups.get(val).push(r);
3172
+ }
3173
+ return groups;
3174
+ }
3175
+ function summarizeMetrics(results, metricName) {
3176
+ const values = extractMetric(results, metricName);
3177
+ if (values.length === 0) {
3178
+ return { mean: 0, std: 0, min: 0, max: 0, n: 0 };
3179
+ }
3180
+ return {
3181
+ mean: mean(values),
3182
+ std: standardDeviation(values),
3183
+ min: Math.min(...values),
3184
+ max: Math.max(...values),
3185
+ n: values.length
3186
+ };
3187
+ }
3188
+ function normalCDF(x) {
3189
+ if (x < -8) return 0;
3190
+ if (x > 8) return 1;
3191
+ const a1 = 0.254829592;
3192
+ const a2 = -0.284496736;
3193
+ const a3 = 1.421413741;
3194
+ const a4 = -1.453152027;
3195
+ const a5 = 1.061405429;
3196
+ const p = 0.3275911;
3197
+ const sign2 = x < 0 ? -1 : 1;
3198
+ const absX = Math.abs(x);
3199
+ const t = 1 / (1 + p * absX);
3200
+ const y = 1 - ((((a5 * t + a4) * t + a3) * t + a2) * t + a1) * t * Math.exp(-absX * absX / 2);
3201
+ return 0.5 * (1 + sign2 * y);
3202
+ }
3203
+ function tDistPValue(absT, df) {
3204
+ if (df <= 0) return 1;
3205
+ const z = absT * (1 - 1 / (4 * df)) / Math.sqrt(1 + absT * absT / (2 * df));
3206
+ return 2 * (1 - normalCDF(z));
3207
+ }
3208
+ function tDistCritical(alpha, df) {
3209
+ const p = 1 - alpha / 2;
3210
+ const a = p - 0.5;
3211
+ const r = a * a;
3212
+ let z = a * (2.50662823884 + r * (-18.61500062529 + r * (41.39119773534 + r * -25.44106049637))) / (1 + r * (-8.4735109309 + r * (23.08336743743 + r * (-21.06224101826 + r * 3.13082909833))));
3213
+ const g1 = (z ** 3 + z) / (4 * df);
3214
+ const g2 = (5 * z ** 5 + 16 * z ** 3 + 3 * z) / (96 * df * df);
3215
+ z = z + g1 + g2;
3216
+ return Math.abs(z);
3217
+ }
3218
+ function chiSquaredPValue(chiSq, df) {
3219
+ if (df <= 0) return 1;
3220
+ if (chiSq <= 0) return 1;
3221
+ const z = Math.pow(chiSq / df, 1 / 3) - (1 - 2 / (9 * df));
3222
+ const denom = Math.sqrt(2 / (9 * df));
3223
+ return 1 - normalCDF(z / denom);
3224
+ }
3225
+
3226
+ // src/traits/SimulationLabTraits.ts
3227
+ var SimulationLabTraits = {
3228
+ simulation_lab: {
3229
+ name: "@simulation_lab",
3230
+ description: "Attaches scientific hypothesis testing to any HoloScript composition. Enables parameter sweeps, multi-epoch execution, statistical analysis, and exportable results. The universe gets one sample \u2014 HoloScript gives you infinite. Results are marketplace-sellable as verified simulation data.",
3231
+ params: {
3232
+ hypothesis: {
3233
+ type: "string",
3234
+ required: true,
3235
+ description: "Human-readable hypothesis description."
3236
+ },
3237
+ null_hypothesis: {
3238
+ type: "string",
3239
+ required: false,
3240
+ default: "",
3241
+ description: "Formal null hypothesis (H0). Auto-generated if empty."
3242
+ },
3243
+ alternative_hypothesis: {
3244
+ type: "string",
3245
+ required: false,
3246
+ default: "",
3247
+ description: "Formal alternative hypothesis (H1). Auto-generated if empty."
3248
+ },
3249
+ direction: {
3250
+ type: "string",
3251
+ required: false,
3252
+ default: "different",
3253
+ description: "Expected direction of effect: greater | less | different | equal."
3254
+ },
3255
+ epochs: {
3256
+ type: "number",
3257
+ required: false,
3258
+ default: 1e3,
3259
+ description: "Number of simulation runs per parameter combination. More = higher power."
3260
+ },
3261
+ seed_start: {
3262
+ type: "number",
3263
+ required: false,
3264
+ default: 0,
3265
+ description: "Starting seed for reproducibility. Seeds increment per epoch."
3266
+ },
3267
+ confidence_level: {
3268
+ type: "number",
3269
+ required: false,
3270
+ default: 0.95,
3271
+ description: "Confidence level for statistical tests (0.0 - 1.0). Default 0.95 = \u03B1=0.05."
3272
+ },
3273
+ metrics: {
3274
+ type: "string[]",
3275
+ required: true,
3276
+ description: "List of metric names to collect each epoch. Must match emitted metric events."
3277
+ },
3278
+ statistical_test: {
3279
+ type: "string",
3280
+ required: false,
3281
+ default: "auto",
3282
+ description: "Statistical test to use: t_test | mann_whitney_u | chi_squared | auto. Auto selects based on data distribution."
3283
+ },
3284
+ export_training_data: {
3285
+ type: "boolean",
3286
+ required: false,
3287
+ default: false,
3288
+ description: "Whether to export results as training data for DataForge pipeline."
3289
+ },
3290
+ marketplace_publishable: {
3291
+ type: "boolean",
3292
+ required: false,
3293
+ default: false,
3294
+ description: "Whether to package results for marketplace listing as verified simulation data."
3295
+ },
3296
+ max_duration_ms: {
3297
+ type: "number",
3298
+ required: false,
3299
+ default: 3e5,
3300
+ description: "Maximum wall-clock time for the entire experiment (5 min default). Prevents runaway simulations."
3301
+ },
3302
+ worker_count: {
3303
+ type: "number",
3304
+ required: false,
3305
+ default: 4,
3306
+ description: "Number of parallel workers for epoch execution."
3307
+ }
3308
+ },
3309
+ validator: (params) => {
3310
+ if (!params.hypothesis || typeof params.hypothesis !== "string") return false;
3311
+ if (!params.metrics || !Array.isArray(params.metrics) || params.metrics.length === 0)
3312
+ return false;
3313
+ if (params.epochs !== void 0 && (params.epochs < 1 || params.epochs > 1e6))
3314
+ return false;
3315
+ if (params.confidence_level !== void 0 && (params.confidence_level <= 0 || params.confidence_level >= 1))
3316
+ return false;
3317
+ if (params.direction !== void 0) {
3318
+ if (!["greater", "less", "different", "equal"].includes(params.direction)) return false;
3319
+ }
3320
+ if (params.statistical_test !== void 0) {
3321
+ if (!["t_test", "mann_whitney_u", "chi_squared", "auto"].includes(params.statistical_test))
3322
+ return false;
3323
+ }
3324
+ return true;
3325
+ },
3326
+ composesWith: [
3327
+ "@tradeable",
3328
+ "@depreciating",
3329
+ "@bonding_curved",
3330
+ "@taxable_wealth",
3331
+ "@pid_controlled"
3332
+ ],
3333
+ compiler_hints: {
3334
+ requires_runtime: [
3335
+ "SimulationRuntime.runExperiment",
3336
+ "SimulationRuntime.collectMetrics",
3337
+ "SimulationRuntime.runStatisticalTest",
3338
+ "SimulationRuntime.exportResults"
3339
+ ],
3340
+ thread_safety: "worker_thread",
3341
+ performance_budget_ms: 3e5,
3342
+ // Experiment budget, not per-frame
3343
+ batch_mode: true
3344
+ }
3345
+ }
3346
+ };
3347
+ function getSimulationTraitNames() {
3348
+ return Object.keys(SimulationLabTraits).map((k) => SimulationLabTraits[k].name);
3349
+ }
3350
+ function getSimulationTrait(name) {
3351
+ const key = name.startsWith("@") ? name.slice(1) : name;
3352
+ return SimulationLabTraits[key];
3353
+ }
3354
+
3355
+ // src/time.ts
3356
+ function now() {
3357
+ return Date.now();
3358
+ }
3359
+ function hrTime() {
3360
+ if (typeof performance !== "undefined") {
3361
+ return performance.now();
3362
+ }
3363
+ return Date.now();
3364
+ }
3365
+ function sleep(ms) {
3366
+ return new Promise((resolve) => setTimeout(resolve, ms));
3367
+ }
3368
+ async function waitUntil(condition, options = {}) {
3369
+ const { timeout = 3e4, interval = 100 } = options;
3370
+ const startTime = now();
3371
+ while (true) {
3372
+ if (await condition()) return;
3373
+ if (now() - startTime > timeout) {
3374
+ throw new Error("waitUntil timeout");
3375
+ }
3376
+ await sleep(interval);
3377
+ }
3378
+ }
3379
+ async function withTimeout(fn, ms) {
3380
+ return Promise.race([
3381
+ fn(),
3382
+ new Promise((_, reject) => setTimeout(() => reject(new Error("Timeout")), ms))
3383
+ ]);
3384
+ }
3385
+ async function retry(fn, options = {}) {
3386
+ const { maxAttempts = 3, initialDelay = 1e3, maxDelay = 3e4, factor = 2, onRetry } = options;
3387
+ let lastError;
3388
+ let delay = initialDelay;
3389
+ for (let attempt = 1; attempt <= maxAttempts; attempt++) {
3390
+ try {
3391
+ return await fn();
3392
+ } catch (error) {
3393
+ lastError = error instanceof Error ? error : new Error(String(error));
3394
+ if (attempt === maxAttempts) break;
3395
+ onRetry?.(lastError, attempt);
3396
+ await sleep(delay);
3397
+ delay = Math.min(delay * factor, maxDelay);
3398
+ }
3399
+ }
3400
+ throw lastError;
3401
+ }
3402
+ function debounce(fn, ms) {
3403
+ let timeoutId = null;
3404
+ return ((...args) => {
3405
+ if (timeoutId) clearTimeout(timeoutId);
3406
+ timeoutId = setTimeout(() => {
3407
+ timeoutId = null;
3408
+ fn(...args);
3409
+ }, ms);
3410
+ });
3411
+ }
3412
+ function throttle(fn, ms) {
3413
+ let lastCall = 0;
3414
+ let timeoutId = null;
3415
+ return ((...args) => {
3416
+ const elapsed = now() - lastCall;
3417
+ if (elapsed >= ms) {
3418
+ lastCall = now();
3419
+ fn(...args);
3420
+ } else if (!timeoutId) {
3421
+ timeoutId = setTimeout(() => {
3422
+ lastCall = now();
3423
+ timeoutId = null;
3424
+ fn(...args);
3425
+ }, ms - elapsed);
3426
+ }
3427
+ });
3428
+ }
3429
+ async function measure(fn) {
3430
+ const start = hrTime();
3431
+ const result = await fn();
3432
+ const duration = hrTime() - start;
3433
+ return { result, duration };
3434
+ }
3435
+ async function timed(label, fn) {
3436
+ const start = hrTime();
3437
+ try {
3438
+ return await fn();
3439
+ } finally {
3440
+ const duration = hrTime() - start;
3441
+ void duration;
3442
+ }
3443
+ }
3444
+ var Stopwatch = class {
3445
+ startTime = 0;
3446
+ pausedTime = 0;
3447
+ running = false;
3448
+ start() {
3449
+ if (!this.running) {
3450
+ this.startTime = hrTime() - this.pausedTime;
3451
+ this.running = true;
3452
+ }
3453
+ return this;
3454
+ }
3455
+ stop() {
3456
+ if (this.running) {
3457
+ this.pausedTime = hrTime() - this.startTime;
3458
+ this.running = false;
3459
+ }
3460
+ return this.pausedTime;
3461
+ }
3462
+ reset() {
3463
+ this.startTime = 0;
3464
+ this.pausedTime = 0;
3465
+ this.running = false;
3466
+ return this;
3467
+ }
3468
+ restart() {
3469
+ return this.reset().start();
3470
+ }
3471
+ get elapsed() {
3472
+ if (this.running) {
3473
+ return hrTime() - this.startTime;
3474
+ }
3475
+ return this.pausedTime;
3476
+ }
3477
+ get isRunning() {
3478
+ return this.running;
3479
+ }
3480
+ lap() {
3481
+ const elapsed = this.elapsed;
3482
+ this.restart();
3483
+ return elapsed;
3484
+ }
3485
+ };
3486
+ var IntervalTimer = class {
3487
+ intervalId = null;
3488
+ callback;
3489
+ intervalMs;
3490
+ isPaused = false;
3491
+ constructor(callback, intervalMs) {
3492
+ this.callback = callback;
3493
+ this.intervalMs = intervalMs;
3494
+ }
3495
+ start() {
3496
+ if (!this.intervalId && !this.isPaused) {
3497
+ this.intervalId = setInterval(this.callback, this.intervalMs);
3498
+ }
3499
+ return this;
3500
+ }
3501
+ stop() {
3502
+ if (this.intervalId) {
3503
+ clearInterval(this.intervalId);
3504
+ this.intervalId = null;
3505
+ }
3506
+ this.isPaused = false;
3507
+ return this;
3508
+ }
3509
+ pause() {
3510
+ if (this.intervalId) {
3511
+ clearInterval(this.intervalId);
3512
+ this.intervalId = null;
3513
+ this.isPaused = true;
3514
+ }
3515
+ return this;
3516
+ }
3517
+ resume() {
3518
+ if (this.isPaused) {
3519
+ this.isPaused = false;
3520
+ this.intervalId = setInterval(this.callback, this.intervalMs);
3521
+ }
3522
+ return this;
3523
+ }
3524
+ get running() {
3525
+ return this.intervalId !== null;
3526
+ }
3527
+ get paused() {
3528
+ return this.isPaused;
3529
+ }
3530
+ };
3531
+ var CountdownTimer = class {
3532
+ remainingMs;
3533
+ startTime = 0;
3534
+ running = false;
3535
+ onTick;
3536
+ onComplete;
3537
+ tickIntervalId = null;
3538
+ constructor(durationMs, options = {}) {
3539
+ this.remainingMs = durationMs;
3540
+ this.onTick = options.onTick;
3541
+ this.onComplete = options.onComplete;
3542
+ if (options.onTick && options.tickInterval) {
3543
+ this.tickIntervalId = setInterval(() => {
3544
+ if (this.running) {
3545
+ this.onTick?.(this.remaining);
3546
+ }
3547
+ }, options.tickInterval);
3548
+ }
3549
+ }
3550
+ start() {
3551
+ if (!this.running && this.remainingMs > 0) {
3552
+ this.startTime = hrTime();
3553
+ this.running = true;
3554
+ this.scheduleCompletion();
3555
+ }
3556
+ return this;
3557
+ }
3558
+ pause() {
3559
+ if (this.running) {
3560
+ this.remainingMs = Math.max(0, this.remainingMs - (hrTime() - this.startTime));
3561
+ this.running = false;
3562
+ }
3563
+ return this;
3564
+ }
3565
+ resume() {
3566
+ return this.start();
3567
+ }
3568
+ reset(durationMs) {
3569
+ this.running = false;
3570
+ this.remainingMs = durationMs ?? this.remainingMs;
3571
+ return this;
3572
+ }
3573
+ stop() {
3574
+ this.running = false;
3575
+ if (this.tickIntervalId) {
3576
+ clearInterval(this.tickIntervalId);
3577
+ this.tickIntervalId = null;
3578
+ }
3579
+ return this;
3580
+ }
3581
+ get remaining() {
3582
+ if (this.running) {
3583
+ return Math.max(0, this.remainingMs - (hrTime() - this.startTime));
3584
+ }
3585
+ return this.remainingMs;
3586
+ }
3587
+ get isRunning() {
3588
+ return this.running;
3589
+ }
3590
+ get isComplete() {
3591
+ return this.remaining <= 0;
3592
+ }
3593
+ scheduleCompletion() {
3594
+ setTimeout(() => {
3595
+ if (this.running && this.remaining <= 0) {
3596
+ this.running = false;
3597
+ this.onComplete?.();
3598
+ }
3599
+ }, this.remainingMs);
3600
+ }
3601
+ };
3602
+ var FrameTimer = class {
3603
+ lastFrameTime = 0;
3604
+ deltaTime = 0;
3605
+ frameCount = 0;
3606
+ fps = 0;
3607
+ fpsUpdateInterval = 1e3;
3608
+ lastFpsUpdate = 0;
3609
+ framesSinceLastFpsUpdate = 0;
3610
+ /**
3611
+ * Call at the start of each frame
3612
+ */
3613
+ update() {
3614
+ const currentTime = hrTime();
3615
+ if (this.lastFrameTime > 0) {
3616
+ this.deltaTime = (currentTime - this.lastFrameTime) / 1e3;
3617
+ }
3618
+ this.lastFrameTime = currentTime;
3619
+ this.frameCount++;
3620
+ this.framesSinceLastFpsUpdate++;
3621
+ if (currentTime - this.lastFpsUpdate >= this.fpsUpdateInterval) {
3622
+ this.fps = this.framesSinceLastFpsUpdate * 1e3 / (currentTime - this.lastFpsUpdate);
3623
+ this.lastFpsUpdate = currentTime;
3624
+ this.framesSinceLastFpsUpdate = 0;
3625
+ }
3626
+ }
3627
+ /**
3628
+ * Get delta time in seconds since last frame
3629
+ */
3630
+ get delta() {
3631
+ return this.deltaTime;
3632
+ }
3633
+ /**
3634
+ * Get delta time in milliseconds since last frame
3635
+ */
3636
+ get deltaMs() {
3637
+ return this.deltaTime * 1e3;
3638
+ }
3639
+ /**
3640
+ * Get total frame count
3641
+ */
3642
+ get frames() {
3643
+ return this.frameCount;
3644
+ }
3645
+ /**
3646
+ * Get current FPS (frames per second)
3647
+ */
3648
+ get currentFps() {
3649
+ return this.fps;
3650
+ }
3651
+ /**
3652
+ * Get total elapsed time in seconds
3653
+ */
3654
+ get totalTime() {
3655
+ return this.lastFrameTime / 1e3;
3656
+ }
3657
+ /**
3658
+ * Reset the timer
3659
+ */
3660
+ reset() {
3661
+ this.lastFrameTime = 0;
3662
+ this.deltaTime = 0;
3663
+ this.frameCount = 0;
3664
+ this.fps = 0;
3665
+ this.lastFpsUpdate = 0;
3666
+ this.framesSinceLastFpsUpdate = 0;
3667
+ }
3668
+ };
3669
+ function schedule(callback, delayMs) {
3670
+ const timeoutId = setTimeout(callback, delayMs);
3671
+ return () => clearTimeout(timeoutId);
3672
+ }
3673
+ function scheduleInterval(callback, intervalMs) {
3674
+ const intervalId = setInterval(callback, intervalMs);
3675
+ return () => clearInterval(intervalId);
3676
+ }
3677
+ function scheduleFrame(callback) {
3678
+ if (typeof requestAnimationFrame !== "undefined") {
3679
+ const id2 = requestAnimationFrame(callback);
3680
+ return () => cancelAnimationFrame(id2);
3681
+ }
3682
+ const id = setTimeout(() => callback(hrTime()), 16);
3683
+ return () => clearTimeout(id);
3684
+ }
3685
+ function createTicker(callback, targetFps = 60) {
3686
+ const frameTime = 1e3 / targetFps;
3687
+ let lastTime = 0;
3688
+ let running = false;
3689
+ let animationId;
3690
+ const tick = (currentTime) => {
3691
+ if (!running) return;
3692
+ if (lastTime > 0) {
3693
+ const delta = (currentTime - lastTime) / 1e3;
3694
+ callback(delta);
3695
+ }
3696
+ lastTime = currentTime;
3697
+ if (typeof requestAnimationFrame !== "undefined") {
3698
+ animationId = requestAnimationFrame(tick);
3699
+ } else {
3700
+ animationId = setTimeout(() => tick(hrTime()), frameTime);
3701
+ }
3702
+ };
3703
+ return {
3704
+ start: () => {
3705
+ if (!running) {
3706
+ running = true;
3707
+ lastTime = 0;
3708
+ if (typeof requestAnimationFrame !== "undefined") {
3709
+ animationId = requestAnimationFrame(tick);
3710
+ } else {
3711
+ tick(hrTime());
3712
+ }
3713
+ }
3714
+ },
3715
+ stop: () => {
3716
+ running = false;
3717
+ if (typeof cancelAnimationFrame !== "undefined") {
3718
+ cancelAnimationFrame(animationId);
3719
+ } else {
3720
+ clearTimeout(animationId);
3721
+ }
3722
+ }
3723
+ };
3724
+ }
3725
+ var DateTime = {
3726
+ /**
3727
+ * Format a date as ISO string
3728
+ */
3729
+ toISO(date = /* @__PURE__ */ new Date()) {
3730
+ return date.toISOString();
3731
+ },
3732
+ /**
3733
+ * Format a date as local string
3734
+ */
3735
+ toLocal(date = /* @__PURE__ */ new Date()) {
3736
+ return date.toLocaleString();
3737
+ },
3738
+ /**
3739
+ * Format a date using a pattern
3740
+ * Supports: YYYY, MM, DD, HH, mm, ss, SSS
3741
+ */
3742
+ format(date, pattern) {
3743
+ const pad = (n, width) => String(n).padStart(width, "0");
3744
+ return pattern.replace("YYYY", String(date.getFullYear())).replace("MM", pad(date.getMonth() + 1, 2)).replace("DD", pad(date.getDate(), 2)).replace("HH", pad(date.getHours(), 2)).replace("mm", pad(date.getMinutes(), 2)).replace("ss", pad(date.getSeconds(), 2)).replace("SSS", pad(date.getMilliseconds(), 3));
3745
+ },
3746
+ /**
3747
+ * Parse a date string
3748
+ */
3749
+ parse(dateString) {
3750
+ return new Date(dateString);
3751
+ },
3752
+ /**
3753
+ * Get difference between two dates in various units
3754
+ */
3755
+ diff(date1, date2, unit = "ms") {
3756
+ const diffMs = date1.getTime() - date2.getTime();
3757
+ switch (unit) {
3758
+ case "ms":
3759
+ return diffMs;
3760
+ case "s":
3761
+ return diffMs / 1e3;
3762
+ case "m":
3763
+ return diffMs / 6e4;
3764
+ case "h":
3765
+ return diffMs / 36e5;
3766
+ case "d":
3767
+ return diffMs / 864e5;
3768
+ }
3769
+ },
3770
+ /**
3771
+ * Add time to a date
3772
+ */
3773
+ add(date, amount, unit) {
3774
+ const _ms = DateTime.diff(new Date(amount), /* @__PURE__ */ new Date(0), "ms");
3775
+ const multipliers = { ms: 1, s: 1e3, m: 6e4, h: 36e5, d: 864e5 };
3776
+ return new Date(date.getTime() + amount * multipliers[unit]);
3777
+ },
3778
+ /**
3779
+ * Check if a date is today
3780
+ */
3781
+ isToday(date) {
3782
+ const today = /* @__PURE__ */ new Date();
3783
+ return date.getDate() === today.getDate() && date.getMonth() === today.getMonth() && date.getFullYear() === today.getFullYear();
3784
+ },
3785
+ /**
3786
+ * Get start of day
3787
+ */
3788
+ startOfDay(date = /* @__PURE__ */ new Date()) {
3789
+ const result = new Date(date);
3790
+ result.setHours(0, 0, 0, 0);
3791
+ return result;
3792
+ },
3793
+ /**
3794
+ * Get end of day
3795
+ */
3796
+ endOfDay(date = /* @__PURE__ */ new Date()) {
3797
+ const result = new Date(date);
3798
+ result.setHours(23, 59, 59, 999);
3799
+ return result;
3800
+ }
3801
+ };
3802
+
3803
+ // src/index.ts
3804
+ function print(...args) {
3805
+ console.log(...args);
3806
+ }
3807
+ function printError(...args) {
3808
+ console.error(...args);
3809
+ }
3810
+ function printWarn(...args) {
3811
+ console.warn(...args);
3812
+ }
3813
+ function assert(condition, message) {
3814
+ if (!condition) {
3815
+ throw new Error(message ?? "Assertion failed");
3816
+ }
3817
+ }
3818
+ function assertDefined(value, message) {
3819
+ if (value === null || value === void 0) {
3820
+ throw new Error(message ?? "Value is null or undefined");
3821
+ }
3822
+ }
3823
+ function unreachable(message) {
3824
+ throw new Error(message ?? "Unreachable code reached");
3825
+ }
3826
+ function todo(message) {
3827
+ throw new Error(`TODO: ${message ?? "Not implemented"}`);
3828
+ }
3829
+ function clone(value) {
3830
+ if (value === null || typeof value !== "object") {
3831
+ return value;
3832
+ }
3833
+ if (Array.isArray(value)) {
3834
+ return value.map(clone);
3835
+ }
3836
+ if (value instanceof Date) {
3837
+ return new Date(value.getTime());
3838
+ }
3839
+ if (value instanceof Map) {
3840
+ return new Map([...value].map(([k, v]) => [clone(k), clone(v)]));
3841
+ }
3842
+ if (value instanceof Set) {
3843
+ return new Set([...value].map(clone));
3844
+ }
3845
+ const result = {};
3846
+ for (const key in value) {
3847
+ if (Object.prototype.hasOwnProperty.call(value, key)) {
3848
+ result[key] = clone(value[key]);
3849
+ }
3850
+ }
3851
+ return result;
3852
+ }
3853
+ function equals(a, b) {
3854
+ if (a === b) return true;
3855
+ if (a === null || b === null) return false;
3856
+ if (typeof a !== typeof b) return false;
3857
+ if (typeof a !== "object") return false;
3858
+ if (Array.isArray(a) && Array.isArray(b)) {
3859
+ if (a.length !== b.length) return false;
3860
+ return a.every((item, i) => equals(item, b[i]));
3861
+ }
3862
+ if (a instanceof Date && b instanceof Date) {
3863
+ return a.getTime() === b.getTime();
3864
+ }
3865
+ if (a instanceof Map && b instanceof Map) {
3866
+ if (a.size !== b.size) return false;
3867
+ for (const [key, value] of a) {
3868
+ if (!b.has(key) || !equals(value, b.get(key))) return false;
3869
+ }
3870
+ return true;
3871
+ }
3872
+ if (a instanceof Set && b instanceof Set) {
3873
+ if (a.size !== b.size) return false;
3874
+ for (const value of a) {
3875
+ if (!b.has(value)) return false;
3876
+ }
3877
+ return true;
3878
+ }
3879
+ const keysA = Object.keys(a);
3880
+ const keysB = Object.keys(b);
3881
+ if (keysA.length !== keysB.length) return false;
3882
+ return keysA.every(
3883
+ (key) => equals(a[key], b[key])
3884
+ );
3885
+ }
3886
+ function pipe(value, ...fns) {
3887
+ return fns.reduce((acc, fn) => fn(acc), value);
3888
+ }
3889
+ function compose(...fns) {
3890
+ return (value) => fns.reduceRight((acc, fn) => fn(acc), value);
3891
+ }
3892
+ function identity(value) {
3893
+ return value;
3894
+ }
3895
+ function noop() {
3896
+ }
3897
+ function constant(value) {
3898
+ return () => value;
3899
+ }
3900
+ // Annotate the CommonJS export names for ESM import in node:
3901
+ 0 && (module.exports = {
3902
+ AABB,
3903
+ CountdownTimer,
3904
+ DEFAULT_BONDING_CURVE,
3905
+ DEFAULT_DEPRECIATION,
3906
+ DEFAULT_PID,
3907
+ DEFAULT_WEALTH_TAX,
3908
+ DEG_TO_RAD,
3909
+ DateTime,
3910
+ EPSILON,
3911
+ EconomicTraits,
3912
+ EventBus,
3913
+ FrameTimer,
3914
+ HALF_PI,
3915
+ HoloMap,
3916
+ HoloSet,
3917
+ IntervalTimer,
3918
+ List,
3919
+ MATERIAL_PRESETS,
3920
+ Map,
3921
+ PI,
3922
+ PriorityQueue,
3923
+ Quaternion,
3924
+ RAD_TO_DEG,
3925
+ Ray,
3926
+ Set,
3927
+ SimulationLabTraits,
3928
+ SpatialGrid,
3929
+ Stopwatch,
3930
+ TAU,
3931
+ Transform,
3932
+ Vec3,
3933
+ aabb,
3934
+ aabbMath,
3935
+ arrayToQuat,
3936
+ arrayToVec3,
3937
+ assert,
3938
+ assertDefined,
3939
+ bondingCurveBuyCost,
3940
+ bondingCurvePrice,
3941
+ bondingCurveSellRefund,
3942
+ calculateDepreciation,
3943
+ calculateRedistribution,
3944
+ calculateRepairCost,
3945
+ calculateTaxAmount,
3946
+ calculateTaxRate,
3947
+ camelCase,
3948
+ capitalize,
3949
+ center,
3950
+ chars,
3951
+ chiSquaredTest,
3952
+ clamp,
3953
+ clone,
3954
+ cohensD,
3955
+ collapseWhitespace,
3956
+ colorToHex,
3957
+ compose,
3958
+ constant,
3959
+ constantCase,
3960
+ containsIgnoreCase,
3961
+ count,
3962
+ createBoxCollider,
3963
+ createCapsuleCollider,
3964
+ createDualLoopPIDState,
3965
+ createFaucetSinkMetrics,
3966
+ createPBRMaterial,
3967
+ createPIDState,
3968
+ createRigidbody,
3969
+ createSphereCollider,
3970
+ createTicker,
3971
+ debounce,
3972
+ dedent,
3973
+ degToRad,
3974
+ depreciatedValue,
3975
+ distance,
3976
+ endsWithIgnoreCase,
3977
+ equals,
3978
+ escapeHtml,
3979
+ escapeRegex,
3980
+ executeTrade,
3981
+ expandSweep,
3982
+ extractMetric,
3983
+ extractTraits,
3984
+ format,
3985
+ formatBytes,
3986
+ formatDuration,
3987
+ formatNumber,
3988
+ fract,
3989
+ generateSweepCombinations,
3990
+ generateTxHash,
3991
+ getEconomicTrait,
3992
+ getEconomicTraitNames,
3993
+ getRequiredPermissions,
3994
+ getSimulationTrait,
3995
+ getSimulationTraitNames,
3996
+ groupByParameter,
3997
+ hrTime,
3998
+ hsl,
3999
+ identity,
4000
+ indent,
4001
+ inverseLerp,
4002
+ isAlpha,
4003
+ isAlphanumeric,
4004
+ isBlank,
4005
+ isDestroyed,
4006
+ isNotBlank,
4007
+ isNumeric,
4008
+ isParameterRange,
4009
+ isValidIdentifier,
4010
+ join,
4011
+ kebabCase,
4012
+ lerp,
4013
+ levenshtein,
4014
+ lines,
4015
+ mannWhitneyU,
4016
+ mean,
4017
+ measure,
4018
+ mod,
4019
+ noise,
4020
+ noop,
4021
+ now,
4022
+ numberWithCommas,
4023
+ oneSampleTTest,
4024
+ padLeft,
4025
+ padRight,
4026
+ parseColor,
4027
+ pascalCase,
4028
+ pipe,
4029
+ print,
4030
+ printError,
4031
+ printWarn,
4032
+ quat,
4033
+ quatMath,
4034
+ quatToArray,
4035
+ radToDeg,
4036
+ random,
4037
+ randomString,
4038
+ ray,
4039
+ recordFaucet,
4040
+ recordSink,
4041
+ remap,
4042
+ removePrefix,
4043
+ removeSuffix,
4044
+ removeWhitespace,
4045
+ repeat,
4046
+ resetMetricsPeriod,
4047
+ retry,
4048
+ reverse,
4049
+ rgb,
4050
+ rgba,
4051
+ schedule,
4052
+ scheduleFrame,
4053
+ scheduleInterval,
4054
+ sign,
4055
+ similarity,
4056
+ sleep,
4057
+ slugify,
4058
+ smootherstep,
4059
+ smoothstep,
4060
+ snakeCase,
4061
+ spatialClamp,
4062
+ spatialDegToRad,
4063
+ spatialLerp,
4064
+ spatialPrice,
4065
+ spatialRadToDeg,
4066
+ standardDeviation,
4067
+ standardError,
4068
+ startsWithIgnoreCase,
4069
+ step,
4070
+ summarizeMetrics,
4071
+ tTest,
4072
+ throttle,
4073
+ timed,
4074
+ titleCase,
4075
+ toDegrees,
4076
+ toRadians,
4077
+ todo,
4078
+ transform,
4079
+ truncate,
4080
+ truncateMiddle,
4081
+ unescapeHtml,
4082
+ unreachable,
4083
+ unwrap,
4084
+ updateDualLoopPID,
4085
+ updatePID,
4086
+ uuid,
4087
+ validateTraitComposition,
4088
+ variance,
4089
+ vec2,
4090
+ vec2Math,
4091
+ vec3,
4092
+ vec3Math,
4093
+ vec3ToArray,
4094
+ vec4,
4095
+ waitUntil,
4096
+ withTimeout,
4097
+ wordWrap,
4098
+ words,
4099
+ wrapString
4100
+ });
4101
+ //# sourceMappingURL=index.cjs.map