@adatechnology/game-runtime 0.0.0-stage → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,573 @@
1
+ "use strict";
2
+ var GameRuntime = (() => {
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
7
+ var __export = (target, all) => {
8
+ for (var name in all)
9
+ __defProp(target, name, { get: all[name], enumerable: true });
10
+ };
11
+ var __copyProps = (to, from, except, desc) => {
12
+ if (from && typeof from === "object" || typeof from === "function") {
13
+ for (let key of __getOwnPropNames(from))
14
+ if (!__hasOwnProp.call(to, key) && key !== except)
15
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
16
+ }
17
+ return to;
18
+ };
19
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
20
+
21
+ // src/index.ts
22
+ var index_exports = {};
23
+ __export(index_exports, {
24
+ COMMAND_SYSTEM_ORDER: () => COMMAND_SYSTEM_ORDER,
25
+ DEFERRED_PRIORITY: () => DEFERRED_PRIORITY,
26
+ FRAME_PHASES: () => FRAME_PHASES,
27
+ createCommandBuffer: () => createCommandBuffer,
28
+ createFrameBudget: () => createFrameBudget,
29
+ createScheduler: () => createScheduler,
30
+ startLoop: () => startLoop
31
+ });
32
+
33
+ // ../game-contracts/dist/index.js
34
+ var DEFAULT_COST_ALLOCATION_BYTES = 1024 * 1024;
35
+ var FRAME_PHASES = ["input", "fixedSimulate", "lateSimulate", "present", "render", "idle"];
36
+ var DEFERRED_QUEUE_ID = {
37
+ DESTRUCTION_EVENTS: "destruction.events",
38
+ BREACH_PAINT: "floorplan.breach-paint",
39
+ AUDIO_VOICES: "audio.voices",
40
+ VEHICLE_CREASE: "vehicles.crease"
41
+ };
42
+ var DEFERRED_PRIORITY = {
43
+ [DEFERRED_QUEUE_ID.DESTRUCTION_EVENTS]: { priority: 300, phase: "present" },
44
+ [DEFERRED_QUEUE_ID.BREACH_PAINT]: { priority: 250, phase: "present" },
45
+ [DEFERRED_QUEUE_ID.AUDIO_VOICES]: { priority: 200, phase: "idle", reserveMs: 1 },
46
+ [DEFERRED_QUEUE_ID.VEHICLE_CREASE]: { priority: 100, phase: "idle" }
47
+ };
48
+ var SURFACE_IDS = ["concrete", "asphalt", "wood", "tile", "dirt", "grass", "gravel", "sand", "metal", "water", "glass", "carpet"];
49
+ var GAIT_IDS = ["walk", "run"];
50
+ var LANDING_IDS = ["light", "heavy"];
51
+ var BODY_SOUND_IDS = [
52
+ "jump",
53
+ "cloth_rustle",
54
+ "body_fall",
55
+ "fall_damage",
56
+ "player_hurt",
57
+ "player_breath_run",
58
+ "player_death",
59
+ "bite",
60
+ "grab",
61
+ "punch_swing",
62
+ "punch_hit_body",
63
+ "punch_hit_face",
64
+ "punch_hit_object",
65
+ "kick_swing",
66
+ "kick_hit",
67
+ "kick_hit_object",
68
+ "shove_two_hands",
69
+ "knife_swing",
70
+ "knife_stab",
71
+ "knife_slash",
72
+ "knife_hit_object",
73
+ "blunt_swing",
74
+ "blunt_hit",
75
+ "blunt_hit_object",
76
+ "axe_swing",
77
+ "axe_chop",
78
+ "axe_hit_object"
79
+ ];
80
+ var footstepSoundId = (surface, gait) => `footstep_${surface}_${gait}`;
81
+ var FOOTSTEP_SOUND_IDS = SURFACE_IDS.flatMap((surface) => GAIT_IDS.map((gait) => footstepSoundId(surface, gait)));
82
+ var LAND_SOUND_IDS = SURFACE_IDS.flatMap((surface) => LANDING_IDS.map((landing) => `land_${surface}_${landing}`));
83
+ var BODY_FOLEY_IDS = [...FOOTSTEP_SOUND_IDS, ...LAND_SOUND_IDS, ...BODY_SOUND_IDS];
84
+
85
+ // src/budget-entry.ts
86
+ var DEFAULT_MIN_EVERY_FRAMES = 4;
87
+ function createQueueEntry(queue, options) {
88
+ return {
89
+ queue,
90
+ phase: options.phase ?? "idle",
91
+ priority: options.priority,
92
+ minEveryFrames: options.minEveryFrames ?? DEFAULT_MIN_EVERY_FRAMES,
93
+ reserveMs: options.reserveMs ?? 0,
94
+ reserveLeft: 0,
95
+ waitingFrames: 0,
96
+ maxWaitingFrames: 0,
97
+ ranUnits: 0,
98
+ spentMs: 0,
99
+ forced: 0,
100
+ lastPending: 0
101
+ };
102
+ }
103
+ function insertByPriority(entries, entry) {
104
+ let index = entries.length;
105
+ while (index > 0 && entries[index - 1].priority < entry.priority) index--;
106
+ entries.splice(index, 0, entry);
107
+ }
108
+ function queueStats(entry) {
109
+ return {
110
+ id: entry.queue.id,
111
+ pending: entry.lastPending,
112
+ ranUnits: entry.ranUnits,
113
+ spentMs: entry.spentMs,
114
+ framesWaiting: entry.waitingFrames,
115
+ maxFramesWaiting: entry.maxWaitingFrames,
116
+ forced: entry.forced
117
+ };
118
+ }
119
+
120
+ // src/clock.ts
121
+ var MICROS_PER_SECOND = 1e6;
122
+ var toMicros = (seconds) => Math.round(seconds * MICROS_PER_SECOND);
123
+ function defaultClock() {
124
+ if (typeof performance !== "undefined" && typeof performance.now === "function") return () => performance.now();
125
+ return () => Date.now();
126
+ }
127
+
128
+ // src/budget.ts
129
+ var DEFAULT_MS = 4;
130
+ var MAX_RESERVE_SHARE = 0.5;
131
+ function createFrameBudget(options = {}) {
132
+ const clock = options.clock ?? defaultClock();
133
+ const entries = [];
134
+ const reportedQueues = /* @__PURE__ */ new Set();
135
+ let frame = 0;
136
+ let frameOpen = false;
137
+ let debt = 0;
138
+ let common = 0;
139
+ let spentThisFrame = 0;
140
+ let unbounded = false;
141
+ const reservedTotal = () => entries.reduce((sum, entry) => sum + entry.reserveMs, 0);
142
+ const beginFrame = () => {
143
+ frame++;
144
+ frameOpen = true;
145
+ spentThisFrame = 0;
146
+ let available = budget.ms;
147
+ for (const entry of entries) {
148
+ entry.reserveLeft = 0;
149
+ if (entry.reserveMs <= 0 || entry.queue.pending(frame) <= 0) continue;
150
+ entry.reserveLeft = Math.min(entry.reserveMs, available);
151
+ available -= entry.reserveLeft;
152
+ }
153
+ common = Math.max(0, available - debt);
154
+ debt = 0;
155
+ };
156
+ const reportError = (error, entry) => {
157
+ if (options.onError) return options.onError(error, { id: entry.queue.id, phase: entry.phase });
158
+ if (reportedQueues.has(entry.queue.id)) return;
159
+ reportedQueues.add(entry.queue.id);
160
+ console.error(`game-runtime: queue ${entry.queue.id} threw`, error);
161
+ };
162
+ const runQueue = (entry, deadline) => {
163
+ try {
164
+ return entry.queue.run(deadline, clock);
165
+ } catch (error) {
166
+ reportError(error, entry);
167
+ return 0;
168
+ }
169
+ };
170
+ const runEntry = (entry, deadline) => {
171
+ const started = clock();
172
+ const ran = runQueue(entry, deadline);
173
+ const spent = Math.max(0, clock() - started);
174
+ entry.ranUnits += ran;
175
+ entry.spentMs += spent;
176
+ entry.waitingFrames = 0;
177
+ spentThisFrame += spent;
178
+ if (unbounded) return;
179
+ const fromReserve = Math.min(entry.reserveLeft, spent);
180
+ entry.reserveLeft -= fromReserve;
181
+ common -= spent - fromReserve;
182
+ if (common < 0) {
183
+ debt = Math.min(budget.ms, debt - common);
184
+ common = 0;
185
+ }
186
+ };
187
+ const drainEntry = (entry) => {
188
+ entry.lastPending = entry.queue.pending(frame);
189
+ if (entry.lastPending <= 0) {
190
+ entry.waitingFrames = 0;
191
+ return;
192
+ }
193
+ if (unbounded) return runEntry(entry, Infinity);
194
+ const allowance = entry.reserveLeft + common;
195
+ if (allowance > 0) return runEntry(entry, clock() + allowance);
196
+ entry.waitingFrames++;
197
+ entry.maxWaitingFrames = Math.max(entry.maxWaitingFrames, entry.waitingFrames);
198
+ if (entry.waitingFrames < entry.minEveryFrames) return;
199
+ entry.forced++;
200
+ runEntry(entry, clock());
201
+ };
202
+ const budget = {
203
+ ms: options.ms ?? DEFAULT_MS,
204
+ register(queue, queueOptions) {
205
+ if (entries.some((candidate) => candidate.queue === queue)) throw new Error(`budget.register(${queue.id}): this queue is already registered`);
206
+ const reserveMs = queueOptions.reserveMs ?? 0;
207
+ if (reservedTotal() + reserveMs > budget.ms * MAX_RESERVE_SHARE) {
208
+ throw new Error(`budget.register(${queue.id}): the reserves would pass half of the ${budget.ms} ms budget`);
209
+ }
210
+ const entry = createQueueEntry(queue, queueOptions);
211
+ insertByPriority(entries, entry);
212
+ queue.attach?.();
213
+ return () => {
214
+ const at = entries.indexOf(entry);
215
+ if (at < 0) return;
216
+ entries.splice(at, 1);
217
+ queue.detach?.();
218
+ };
219
+ },
220
+ beginFrame,
221
+ drain(phase) {
222
+ if (phase === "present" && !frameOpen) beginFrame();
223
+ for (const entry of [...entries]) if (entry.phase === phase) drainEntry(entry);
224
+ if (phase === "idle") frameOpen = false;
225
+ },
226
+ flushAll() {
227
+ for (const entry of entries) entry.queue.flush();
228
+ },
229
+ get unbounded() {
230
+ return unbounded;
231
+ },
232
+ set unbounded(value) {
233
+ unbounded = value;
234
+ },
235
+ stats() {
236
+ return {
237
+ ms: budget.ms,
238
+ spentMs: spentThisFrame,
239
+ debtMs: debt,
240
+ queues: entries.map(queueStats)
241
+ };
242
+ },
243
+ dispose() {
244
+ for (const entry of entries.splice(0)) entry.queue.detach?.();
245
+ }
246
+ };
247
+ return budget;
248
+ }
249
+
250
+ // src/commands.ts
251
+ var COMMAND_SYSTEM_ORDER = -1e4;
252
+ var NONE = [];
253
+ function createCommandBuffer(nextTick) {
254
+ let pending = [];
255
+ return {
256
+ push(kind, payload, tick) {
257
+ pending.push({ kind, payload, tick: tick ?? nextTick() });
258
+ },
259
+ take(tick) {
260
+ if (pending.length === 0) return NONE;
261
+ const due = [];
262
+ const later = [];
263
+ for (const command of pending) (command.tick <= tick ? due : later).push(command);
264
+ pending = later;
265
+ return due;
266
+ },
267
+ clear() {
268
+ pending = [];
269
+ }
270
+ };
271
+ }
272
+
273
+ // src/loop.ts
274
+ function startLoop(scheduler, options = {}) {
275
+ const requestFrame = options.requestFrame ?? globalThis.requestAnimationFrame?.bind(globalThis);
276
+ const cancelFrame = options.cancelFrame ?? globalThis.cancelAnimationFrame?.bind(globalThis);
277
+ if (!requestFrame) throw new Error("startLoop: no requestAnimationFrame here, pass requestFrame");
278
+ let last = options.startMs ?? (typeof performance !== "undefined" ? performance.now() : 0);
279
+ let handle = 0;
280
+ let stopped = false;
281
+ const onFrame = (nowMs) => {
282
+ if (stopped) return;
283
+ handle = requestFrame(onFrame);
284
+ const gap = options.minFrameMs?.() ?? 0;
285
+ if (gap > 0 && nowMs - last < gap) return;
286
+ const realSeconds = (nowMs - last) / 1e3;
287
+ last = nowMs;
288
+ options.onFrame?.(realSeconds);
289
+ scheduler.frame(realSeconds, options.skipSimulation?.() ? { simulate: false } : void 0);
290
+ };
291
+ const onVisibility = () => {
292
+ if (document.visibilityState !== "visible") return;
293
+ if (typeof performance !== "undefined") last = performance.now();
294
+ scheduler.resetClock();
295
+ };
296
+ const hasDocument = typeof document !== "undefined" && typeof document.addEventListener === "function";
297
+ if (hasDocument) document.addEventListener("visibilitychange", onVisibility);
298
+ handle = requestFrame(onFrame);
299
+ return () => {
300
+ stopped = true;
301
+ cancelFrame?.(handle);
302
+ if (hasDocument) document.removeEventListener("visibilitychange", onVisibility);
303
+ };
304
+ }
305
+
306
+ // src/frame-time.ts
307
+ var sanitizeSeconds = (seconds) => Number.isFinite(seconds) && seconds > 0 ? seconds : 0;
308
+ var sanitizeTimeScale = (scale) => Number.isFinite(scale) ? Math.max(0, scale) : 1;
309
+ function resolveFrameTime(realSeconds, exact, residual, config) {
310
+ const given = sanitizeSeconds(realSeconds);
311
+ if (exact) return { seconds: given, micros: toMicros(given), residual };
312
+ const clamped = Math.min(given, config.maxFrameSeconds);
313
+ const micros = toMicros(clamped) + residual;
314
+ const wholeSteps = Math.round(micros / config.fixedMicros);
315
+ const drift = micros - wholeSteps * config.fixedMicros;
316
+ if (config.snapMicros > 0 && wholeSteps >= 1 && Math.abs(drift) <= config.snapMicros) {
317
+ return { seconds: wholeSteps * config.fixedDt, micros: wholeSteps * config.fixedMicros, residual: drift };
318
+ }
319
+ return { seconds: clamped, micros, residual: 0 };
320
+ }
321
+
322
+ // src/phase-runner.ts
323
+ function createPhaseRunner(deps) {
324
+ const { clock, ctx, lists, reportError, fixedDt } = deps;
325
+ const phaseMs = Object.fromEntries(FRAME_PHASES.map((phase) => [phase, 0]));
326
+ let tick = 0;
327
+ const runEntries = (phase) => {
328
+ for (const entry of lists[phase].entries) {
329
+ if (entry.dead) continue;
330
+ try {
331
+ entry.fn(ctx);
332
+ } catch (error) {
333
+ reportError(error, { id: entry.id, phase });
334
+ }
335
+ }
336
+ };
337
+ return {
338
+ runPhase(phase, dt) {
339
+ const started = clock();
340
+ ctx.dt = dt;
341
+ runEntries(phase);
342
+ phaseMs[phase] = clock() - started;
343
+ },
344
+ runFixed(steps) {
345
+ const started = clock();
346
+ ctx.dt = fixedDt;
347
+ for (let substep = 0; substep < steps; substep++) {
348
+ ctx.substep = substep;
349
+ ctx.tick = tick;
350
+ runEntries("fixedSimulate");
351
+ tick++;
352
+ }
353
+ ctx.substep = 0;
354
+ ctx.tick = tick;
355
+ phaseMs.fixedSimulate = clock() - started;
356
+ },
357
+ get tick() {
358
+ return tick;
359
+ },
360
+ phaseMs
361
+ };
362
+ }
363
+
364
+ // src/phases.ts
365
+ function createSystemList(isRunning) {
366
+ let entries = [];
367
+ const waiting = [];
368
+ const insert = (entry) => {
369
+ let index = entries.length;
370
+ while (index > 0 && entries[index - 1].order > entry.order) index--;
371
+ entries.splice(index, 0, entry);
372
+ };
373
+ return {
374
+ add(entry) {
375
+ if (isRunning()) waiting.push(entry);
376
+ else insert(entry);
377
+ },
378
+ remove(entry) {
379
+ entry.dead = true;
380
+ if (!isRunning()) entries = entries.filter((candidate) => candidate !== entry);
381
+ },
382
+ get entries() {
383
+ return entries;
384
+ },
385
+ settle() {
386
+ if (entries.some((entry) => entry.dead)) entries = entries.filter((entry) => !entry.dead);
387
+ for (const entry of waiting.splice(0)) if (!entry.dead) insert(entry);
388
+ },
389
+ clear() {
390
+ for (const entry of entries) entry.dead = true;
391
+ for (const entry of waiting.splice(0)) entry.dead = true;
392
+ entries = isRunning() ? entries : [];
393
+ }
394
+ };
395
+ }
396
+
397
+ // src/scheduler.ts
398
+ function createScheduler(options = {}) {
399
+ const fixedDt = options.fixedDt ?? 1 / 60;
400
+ const fixedMicros = toMicros(fixedDt);
401
+ const maxSubsteps = options.maxSubsteps ?? 4;
402
+ const timeConfig = { fixedMicros, fixedDt, maxFrameSeconds: options.maxFrameSeconds ?? 0.25, snapMicros: Math.round((options.snapMs ?? 0.25) * 1e3) };
403
+ const clock = options.clock ?? defaultClock();
404
+ let accumulator = 0;
405
+ let residual = 0;
406
+ let droppedMicros = 0;
407
+ let substepsLastFrame = 0;
408
+ let running = false;
409
+ let disposed = false;
410
+ let paused = false;
411
+ let scripted = false;
412
+ let timeScale = 1;
413
+ let nextSystem = 0;
414
+ const reportedErrors = /* @__PURE__ */ new Set();
415
+ const lists = Object.fromEntries(FRAME_PHASES.map((phase) => [phase, createSystemList(() => running)]));
416
+ const ctx = { dt: 0, realDt: 0, fixedDt, alpha: 0, frame: 0, tick: 0, substep: 0, simTime: 0, paused: false, scripted: false, simulated: true };
417
+ const reportError = options.onError ?? ((error, system) => {
418
+ if (reportedErrors.has(system.id)) return;
419
+ reportedErrors.add(system.id);
420
+ console.error(`game-runtime: system ${system.id} (${system.phase}) threw`, error);
421
+ });
422
+ const budget = createFrameBudget({ ms: options.budgetMs ?? 4, clock, onError: (error, queue) => reportError(error, { id: `queue:${queue.id}`, phase: queue.phase }) });
423
+ const runner = createPhaseRunner({ clock, ctx, lists, reportError, fixedDt });
424
+ const { runPhase, runFixed } = runner;
425
+ const settleAll = () => {
426
+ for (const phase of FRAME_PHASES) lists[phase].settle();
427
+ };
428
+ const begin = () => {
429
+ running = true;
430
+ budget.beginFrame();
431
+ ctx.frame++;
432
+ ctx.paused = paused;
433
+ ctx.scripted = scripted;
434
+ ctx.tick = runner.tick;
435
+ };
436
+ const end = () => {
437
+ running = false;
438
+ settleAll();
439
+ };
440
+ const simulate = (seconds, micros, exact) => {
441
+ runPhase("input", seconds);
442
+ if (paused) return;
443
+ accumulator += Math.round(micros * timeScale);
444
+ let steps = Math.floor(accumulator / fixedMicros);
445
+ if (!exact && steps > maxSubsteps) {
446
+ droppedMicros += accumulator - maxSubsteps * fixedMicros;
447
+ steps = maxSubsteps;
448
+ accumulator = maxSubsteps * fixedMicros;
449
+ }
450
+ accumulator -= steps * fixedMicros;
451
+ substepsLastFrame = steps;
452
+ runFixed(steps);
453
+ ctx.alpha = accumulator / fixedMicros;
454
+ ctx.simTime += seconds * timeScale;
455
+ runPhase("lateSimulate", seconds * timeScale);
456
+ };
457
+ const frame = (realSeconds, run = {}) => {
458
+ if (running) throw new Error("scheduler.frame: re-entrant call");
459
+ if (disposed) throw new Error("scheduler.frame: the scheduler was disposed");
460
+ const time = resolveFrameTime(realSeconds, run.exact === true, residual, timeConfig);
461
+ residual = time.residual;
462
+ const seconds = time.seconds;
463
+ begin();
464
+ try {
465
+ ctx.simulated = run.simulate !== false;
466
+ ctx.realDt = seconds;
467
+ ctx.alpha = accumulator / fixedMicros;
468
+ substepsLastFrame = 0;
469
+ if (ctx.simulated) simulate(seconds, time.micros, run.exact === true);
470
+ ctx.alpha = accumulator / fixedMicros;
471
+ runPhase("present", paused ? 0 : seconds * timeScale);
472
+ budget.drain("present");
473
+ if (run.render !== false) runPhase("render", seconds);
474
+ runPhase("idle", seconds);
475
+ budget.drain("idle");
476
+ } finally {
477
+ ctx.simulated = true;
478
+ end();
479
+ }
480
+ };
481
+ const advanceStep = (dt, steps) => {
482
+ begin();
483
+ try {
484
+ ctx.simulated = true;
485
+ ctx.realDt = dt;
486
+ ctx.alpha = 0;
487
+ runPhase("input", dt);
488
+ if (!paused) {
489
+ runFixed(steps);
490
+ ctx.simTime += dt;
491
+ runPhase("lateSimulate", dt);
492
+ }
493
+ runPhase("present", paused ? 0 : dt);
494
+ budget.drain("present");
495
+ runPhase("idle", dt);
496
+ budget.drain("idle");
497
+ } finally {
498
+ end();
499
+ }
500
+ };
501
+ const advance = (seconds, advanceOptions = {}) => {
502
+ if (running) throw new Error("scheduler.advance: re-entrant call");
503
+ if (disposed) throw new Error("scheduler.advance: the scheduler was disposed");
504
+ const dt = sanitizeSeconds(advanceOptions.dt ?? fixedDt) || fixedDt;
505
+ const iterations = Math.max(1, Math.round(sanitizeSeconds(seconds) / dt));
506
+ const steps = Math.max(1, Math.round(dt / fixedDt));
507
+ const wasUnbounded = budget.unbounded;
508
+ budget.unbounded = true;
509
+ scripted = true;
510
+ accumulator = 0;
511
+ residual = 0;
512
+ scheduler.commands.clear();
513
+ try {
514
+ for (let i = 0; i < iterations; i++) advanceStep(dt, steps);
515
+ } finally {
516
+ scripted = false;
517
+ ctx.scripted = false;
518
+ budget.unbounded = wasUnbounded;
519
+ accumulator = 0;
520
+ ctx.alpha = 0;
521
+ }
522
+ };
523
+ const scheduler = {
524
+ add(system, systemOptions) {
525
+ if (disposed) return () => void 0;
526
+ const entry = {
527
+ id: systemOptions.id ?? `${systemOptions.phase}#${nextSystem++}`,
528
+ phase: systemOptions.phase,
529
+ fn: system,
530
+ order: systemOptions.order ?? 0,
531
+ dead: false
532
+ };
533
+ lists[entry.phase].add(entry);
534
+ return () => lists[entry.phase].remove(entry);
535
+ },
536
+ frame,
537
+ advance,
538
+ pause() {
539
+ paused = true;
540
+ },
541
+ resume() {
542
+ paused = false;
543
+ },
544
+ get paused() {
545
+ return paused;
546
+ },
547
+ get timeScale() {
548
+ return timeScale;
549
+ },
550
+ set timeScale(value) {
551
+ timeScale = sanitizeTimeScale(value);
552
+ },
553
+ resetClock() {
554
+ accumulator = 0;
555
+ residual = 0;
556
+ },
557
+ budget,
558
+ commands: createCommandBuffer(() => runner.tick),
559
+ stats() {
560
+ return { frame: ctx.frame, tick: runner.tick, substepsLastFrame, droppedSeconds: droppedMicros / MICROS_PER_SECOND, phaseMs: { ...runner.phaseMs }, budget: budget.stats() };
561
+ },
562
+ dispose() {
563
+ disposed = true;
564
+ budget.dispose();
565
+ for (const phase of FRAME_PHASES) lists[phase].clear();
566
+ settleAll();
567
+ }
568
+ };
569
+ return scheduler;
570
+ }
571
+ return __toCommonJS(index_exports);
572
+ })();
573
+ //# sourceMappingURL=index.global.js.map