@oasys/oecs 0.1.0 → 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1,19 +1,16 @@
1
- var F = Object.defineProperty;
2
- var X = (a, t, e) => t in a ? F(a, t, { enumerable: !0, configurable: !0, writable: !0, value: e }) : a[t] = e;
3
- var l = (a, t, e) => X(a, typeof t != "symbol" ? t + "" : t, e);
4
- class Y extends Error {
1
+ class R extends Error {
5
2
  constructor(t, e, s) {
6
3
  super(t), this.is_operational = e, this.context = s, this.name = this.constructor.name, Error.captureStackTrace(this, this.constructor);
7
4
  }
8
5
  }
9
- var u = /* @__PURE__ */ ((a) => (a.EID_MAX_INDEX_OVERFLOW = "EID_MAX_INDEX_OVERFLOW", a.EID_MAX_GEN_OVERFLOW = "EID_MAX_GEN_OVERFLOW", a.COMPONENT_NOT_REGISTERED = "COMPONENT_NOT_REGISTERED", a.ENTITY_NOT_ALIVE = "ENTITY_NOT_ALIVE", a.CIRCULAR_SYSTEM_DEPENDENCY = "CIRCULAR_SYSTEM_DEPENDENCY", a.DUPLICATE_SYSTEM = "DUPLICATE_SYSTEM", a.ARCHETYPE_NOT_FOUND = "ARCHETYPE_NOT_FOUND", a))(u || {});
10
- class g extends Y {
6
+ var d = /* @__PURE__ */ ((a) => (a.EID_MAX_INDEX_OVERFLOW = "EID_MAX_INDEX_OVERFLOW", a.EID_MAX_GEN_OVERFLOW = "EID_MAX_GEN_OVERFLOW", a.COMPONENT_NOT_REGISTERED = "COMPONENT_NOT_REGISTERED", a.ENTITY_NOT_ALIVE = "ENTITY_NOT_ALIVE", a.CIRCULAR_SYSTEM_DEPENDENCY = "CIRCULAR_SYSTEM_DEPENDENCY", a.DUPLICATE_SYSTEM = "DUPLICATE_SYSTEM", a.ARCHETYPE_NOT_FOUND = "ARCHETYPE_NOT_FOUND", a))(d || {});
7
+ class u extends R {
11
8
  constructor(t, e, s) {
12
9
  super(e ?? t, !0, s), this.category = t;
13
10
  }
14
11
  }
15
- var C = /* @__PURE__ */ ((a) => (a.ASSERTION_FAIL_CONDITION = "ASSERTION_FAIL_CONDITION", a.VALIDATION_FAIL_CONDITION = "VALIDATION_FAIL_CONDITION", a))(C || {});
16
- class G extends Y {
12
+ var Y = /* @__PURE__ */ ((a) => (a.ASSERTION_FAIL_CONDITION = "ASSERTION_FAIL_CONDITION", a.VALIDATION_FAIL_CONDITION = "VALIDATION_FAIL_CONDITION", a))(Y || {});
13
+ class X extends R {
17
14
  constructor(t, e, s) {
18
15
  super(e, !1, s), this.category = t;
19
16
  }
@@ -21,17 +18,17 @@ class G extends Y {
21
18
  const P = (a) => Number.isInteger(a) && a >= 0;
22
19
  function b(a, t, e) {
23
20
  if (process.env.NODE_ENV !== "production" && !t(a))
24
- throw new G(
25
- C.VALIDATION_FAIL_CONDITION,
21
+ throw new X(
22
+ Y.VALIDATION_FAIL_CONDITION,
26
23
  `Expected value to meet validation: ${e}`
27
24
  );
28
25
  return a;
29
26
  }
30
- const $ = 4;
31
- class T {
27
+ const C = 4;
28
+ class N {
29
+ _words;
32
30
  constructor(t) {
33
- l(this, "_words");
34
- this._words = t ?? new Array($).fill(0);
31
+ this._words = t ?? new Array(C).fill(0);
35
32
  }
36
33
  has(t) {
37
34
  const e = t >>> 5;
@@ -56,8 +53,8 @@ class T {
56
53
  contains(t) {
57
54
  const e = t._words, s = this._words, n = s.length;
58
55
  for (let r = 0; r < e.length; r++) {
59
- const o = e[r];
60
- if (o !== 0 && (r >= n || (s[r] & o) !== o))
56
+ const i = e[r];
57
+ if (i !== 0 && (r >= n || (s[r] & i) !== i))
61
58
  return !1;
62
59
  }
63
60
  return !0;
@@ -65,22 +62,22 @@ class T {
65
62
  equals(t) {
66
63
  const e = this._words, s = t._words, n = e.length > s.length ? e.length : s.length;
67
64
  for (let r = 0; r < n; r++) {
68
- const o = r < e.length ? e[r] : 0, _ = r < s.length ? s[r] : 0;
69
- if (o !== _) return !1;
65
+ const i = r < e.length ? e[r] : 0, _ = r < s.length ? s[r] : 0;
66
+ if (i !== _) return !1;
70
67
  }
71
68
  return !0;
72
69
  }
73
70
  copy() {
74
- return new T(this._words.slice());
71
+ return new N(this._words.slice());
75
72
  }
76
73
  copy_with_set(t) {
77
74
  const e = t >>> 5, s = e + 1, n = this._words.length > s ? this._words.length : s, r = new Array(n).fill(0);
78
- for (let o = 0; o < this._words.length; o++) r[o] = this._words[o];
79
- return r[e] |= 1 << (t & 31), new T(r);
75
+ for (let i = 0; i < this._words.length; i++) r[i] = this._words[i];
76
+ return r[e] |= 1 << (t & 31), new N(r);
80
77
  }
81
78
  copy_with_clear(t) {
82
79
  const e = this._words.slice(), s = t >>> 5;
83
- return s < e.length && (e[s] &= ~(1 << (t & 31))), new T(e);
80
+ return s < e.length && (e[s] &= ~(1 << (t & 31))), new N(e);
84
81
  }
85
82
  /** FNV-1a hash. Skips trailing zero words so differently-sized arrays with the same bits hash equally. */
86
83
  hash() {
@@ -100,8 +97,8 @@ class T {
100
97
  if (n === 0) continue;
101
98
  const r = s << 5;
102
99
  for (; n !== 0; ) {
103
- const o = n & -n >>> 0, _ = 31 - Math.clz32(o);
104
- t(r + _), n ^= o;
100
+ const i = n & -n >>> 0, _ = 31 - Math.clz32(i);
101
+ t(r + _), n ^= i;
105
102
  }
106
103
  }
107
104
  }
@@ -113,28 +110,28 @@ class T {
113
110
  this._words = s;
114
111
  }
115
112
  }
116
- const D = 20, S = (1 << D) - 1, z = S, W = 31 - D, k = (1 << W) - 1, B = (a, t) => {
113
+ const I = 20, k = (1 << I) - 1, j = k, G = 31 - I, D = (1 << G) - 1, $ = (a, t) => {
117
114
  if (process.env.NODE_ENV !== "production") {
118
- if (a < 0 || a > z)
119
- throw new g(u.EID_MAX_INDEX_OVERFLOW);
120
- if (t < 0 || t > k)
121
- throw new g(u.EID_MAX_GEN_OVERFLOW);
115
+ if (a < 0 || a > j)
116
+ throw new u(d.EID_MAX_INDEX_OVERFLOW);
117
+ if (t < 0 || t > D)
118
+ throw new u(d.EID_MAX_GEN_OVERFLOW);
122
119
  }
123
- return t << D | a;
124
- }, m = (a) => a & S, R = (a) => a >> D, Q = (a) => b(
120
+ return t << I | a;
121
+ }, y = (a) => a & k, q = (a) => a >> I, z = (a) => b(
125
122
  a,
126
123
  P,
127
124
  "ComponentID must be a non-negative integer"
128
- ), K = (a) => b(
125
+ ), W = (a) => b(
129
126
  a,
130
127
  P,
131
128
  "EventID must be a non-negative integer"
132
129
  );
133
- class J {
130
+ class B {
131
+ field_names;
132
+ columns;
133
+ reader;
134
134
  constructor(t) {
135
- l(this, "field_names");
136
- l(this, "columns");
137
- l(this, "reader");
138
135
  this.field_names = t, this.columns = [];
139
136
  for (let s = 0; s < t.length; s++)
140
137
  this.columns.push([]);
@@ -160,36 +157,36 @@ class J {
160
157
  t[e].length = 0;
161
158
  }
162
159
  }
163
- const Z = (a) => b(
160
+ const Q = (a) => b(
164
161
  a,
165
162
  P,
166
163
  "ArchetypeID must be a non-negative integer"
167
164
  );
168
- class H {
165
+ class K {
166
+ id;
167
+ mask;
168
+ has_columns;
169
+ entity_ids = [];
170
+ length = 0;
171
+ edges = [];
172
+ // Sparse array indexed by ComponentID — undefined for absent components.
173
+ // Allows O(1) column group lookup by component.
174
+ column_groups = [];
175
+ // Dense list of ComponentIDs that have columns — used to iterate only
176
+ // data-bearing components in copy/add/remove operations.
177
+ _column_ids = [];
169
178
  constructor(t, e, s) {
170
- l(this, "id");
171
- l(this, "mask");
172
- l(this, "has_columns");
173
- l(this, "entity_ids", []);
174
- l(this, "length", 0);
175
- l(this, "edges", []);
176
- // Sparse array indexed by ComponentID — undefined for absent components.
177
- // Allows O(1) column group lookup by component.
178
- l(this, "column_groups", []);
179
- // Dense list of ComponentIDs that have columns — used to iterate only
180
- // data-bearing components in copy/add/remove operations.
181
- l(this, "_column_ids", []);
182
179
  if (this.id = t, this.mask = e, s)
183
180
  for (let n = 0; n < s.length; n++) {
184
- const r = s[n], o = new Array(r.field_names.length);
181
+ const r = s[n], i = new Array(r.field_names.length);
185
182
  for (let h = 0; h < r.field_names.length; h++)
186
- o[h] = [];
183
+ i[h] = [];
187
184
  const _ = /* @__PURE__ */ Object.create(null);
188
185
  for (let h = 0; h < r.field_names.length; h++)
189
- _[r.field_names[h]] = o[h];
186
+ _[r.field_names[h]] = i[h];
190
187
  this.column_groups[r.component_id] = {
191
188
  layout: r,
192
- columns: o,
189
+ columns: i,
193
190
  record: _
194
191
  }, this._column_ids.push(r.component_id);
195
192
  }
@@ -211,14 +208,14 @@ class H {
211
208
  get_column(t, e) {
212
209
  const s = this.column_groups[t];
213
210
  if (process.env.NODE_ENV !== "production" && !s)
214
- throw new g(
215
- u.COMPONENT_NOT_REGISTERED,
211
+ throw new u(
212
+ d.COMPONENT_NOT_REGISTERED,
216
213
  `Component ${t} not in archetype ${this.id}`
217
214
  );
218
215
  const n = s.layout.field_index[e];
219
216
  if (process.env.NODE_ENV !== "production" && n === void 0)
220
- throw new g(
221
- u.COMPONENT_NOT_REGISTERED,
217
+ throw new u(
218
+ d.COMPONENT_NOT_REGISTERED,
222
219
  `Field "${e}" does not exist on component`
223
220
  );
224
221
  return s.columns[n];
@@ -232,8 +229,8 @@ class H {
232
229
  const n = this.column_groups[e];
233
230
  if (!n) return;
234
231
  const { field_names: r } = n.layout;
235
- for (let o = 0; o < r.length; o++)
236
- n.columns[o][t] = s[r[o]];
232
+ for (let i = 0; i < r.length; i++)
233
+ n.columns[i][t] = s[r[i]];
237
234
  }
238
235
  read_field(t, e, s) {
239
236
  const n = this.column_groups[e];
@@ -244,12 +241,12 @@ class H {
244
241
  /** Copy all shared component columns from source archetype at src_row into dst_row. */
245
242
  copy_shared_from(t, e, s) {
246
243
  const n = t.column_groups, r = this._column_ids;
247
- for (let o = 0; o < r.length; o++) {
248
- const _ = r[o], h = n[_];
244
+ for (let i = 0; i < r.length; i++) {
245
+ const _ = r[i], h = n[_];
249
246
  if (!h) continue;
250
- const i = this.column_groups[_];
251
- for (let c = 0; c < i.columns.length; c++)
252
- i.columns[c][s] = h.columns[c][e];
247
+ const o = this.column_groups[_];
248
+ for (let c = 0; c < o.columns.length; c++)
249
+ o.columns[c][s] = h.columns[c][e];
253
250
  }
254
251
  }
255
252
  /**
@@ -262,8 +259,8 @@ class H {
262
259
  const s = this._column_ids;
263
260
  for (let n = 0; n < s.length; n++) {
264
261
  const r = this.column_groups[s[n]];
265
- for (let o = 0; o < r.columns.length; o++)
266
- r.columns[o].push(0);
262
+ for (let i = 0; i < r.columns.length; i++)
263
+ r.columns[i].push(0);
267
264
  }
268
265
  return this.length++, e;
269
266
  }
@@ -277,17 +274,17 @@ class H {
277
274
  let s = -1;
278
275
  const n = this._column_ids;
279
276
  if (t !== e) {
280
- this.entity_ids[t] = this.entity_ids[e], s = m(this.entity_ids[t]);
277
+ this.entity_ids[t] = this.entity_ids[e], s = y(this.entity_ids[t]);
281
278
  for (let r = 0; r < n.length; r++) {
282
- const o = this.column_groups[n[r]];
283
- for (let _ = 0; _ < o.columns.length; _++)
284
- o.columns[_][t] = o.columns[_][e], o.columns[_].pop();
279
+ const i = this.column_groups[n[r]];
280
+ for (let _ = 0; _ < i.columns.length; _++)
281
+ i.columns[_][t] = i.columns[_][e], i.columns[_].pop();
285
282
  }
286
283
  } else
287
284
  for (let r = 0; r < n.length; r++) {
288
- const o = this.column_groups[n[r]];
289
- for (let _ = 0; _ < o.columns.length; _++)
290
- o.columns[_].pop();
285
+ const i = this.column_groups[n[r]];
286
+ for (let _ = 0; _ < i.columns.length; _++)
287
+ i.columns[_].pop();
291
288
  }
292
289
  return this.entity_ids.pop(), this.length--, s;
293
290
  }
@@ -300,7 +297,7 @@ class H {
300
297
  remove_entity_tag(t) {
301
298
  const e = this.length - 1;
302
299
  let s = -1;
303
- return t !== e && (this.entity_ids[t] = this.entity_ids[e], s = m(this.entity_ids[t])), this.entity_ids.pop(), this.length--, s;
300
+ return t !== e && (this.entity_ids[t] = this.entity_ids[e], s = y(this.entity_ids[t])), this.entity_ids.pop(), this.length--, s;
304
301
  }
305
302
  get_edge(t) {
306
303
  return this.edges[t];
@@ -309,63 +306,63 @@ class H {
309
306
  this.edges[t] = e;
310
307
  }
311
308
  }
312
- function j(a, t, e) {
309
+ function F(a, t, e) {
313
310
  const s = a.get(t);
314
311
  s !== void 0 ? s.push(e) : a.set(t, [e]);
315
312
  }
316
- const w = -1, M = Object.freeze(/* @__PURE__ */ Object.create(null));
317
- class tt {
313
+ const m = -1, V = Object.freeze(/* @__PURE__ */ Object.create(null));
314
+ class J {
315
+ // --- Entity ID management ---
316
+ // Generational slot allocator: entity_generations[index] holds the current
317
+ // generation for that slot. Free indices are recycled via a stack.
318
+ entity_generations = [];
319
+ entity_high_water = 0;
320
+ entity_free_indices = [];
321
+ entity_alive_count = 0;
322
+ // --- Component metadata ---
323
+ // Parallel array indexed by ComponentID: field_names and field_index
324
+ // for building archetype column layouts.
325
+ component_metas = [];
326
+ component_count = 0;
327
+ // --- Event channels ---
328
+ // Parallel array indexed by EventID: each channel holds SoA columns + reader.
329
+ event_channels = [];
330
+ event_count = 0;
331
+ // --- Archetype management ---
332
+ archetypes = [];
333
+ // Hash-bucketed lookup: BitSet.hash() → ArchetypeID[] for deduplication
334
+ archetype_map = /* @__PURE__ */ new Map();
335
+ next_archetype_id = 0;
336
+ // Inverted index: ComponentID → set of ArchetypeIDs containing that component.
337
+ // Used by get_matching_archetypes to start from the smallest set.
338
+ component_index = /* @__PURE__ */ new Map();
339
+ // Registered queries: the Store pushes newly-created archetypes into matching
340
+ // query result arrays, so queries are always up-to-date.
341
+ registered_queries = [];
342
+ empty_archetype_id;
343
+ // entity_index → ArchetypeID (UNASSIGNED = not in any archetype)
344
+ entity_archetype = [];
345
+ // entity_index → row within its archetype (UNASSIGNED = no row)
346
+ entity_row = [];
347
+ // --- Deferred operation buffers ---
348
+ // Flat parallel arrays: pending_add_ids[i], pending_add_defs[i], pending_add_values[i]
349
+ // describe one deferred add. No per-operation object allocation.
350
+ pending_destroy = [];
351
+ pending_add_ids = [];
352
+ pending_add_defs = [];
353
+ pending_add_values = [];
354
+ pending_remove_ids = [];
355
+ pending_remove_defs = [];
318
356
  constructor() {
319
- // --- Entity ID management ---
320
- // Generational slot allocator: entity_generations[index] holds the current
321
- // generation for that slot. Free indices are recycled via a stack.
322
- l(this, "entity_generations", []);
323
- l(this, "entity_high_water", 0);
324
- l(this, "entity_free_indices", []);
325
- l(this, "entity_alive_count", 0);
326
- // --- Component metadata ---
327
- // Parallel array indexed by ComponentID: field_names and field_index
328
- // for building archetype column layouts.
329
- l(this, "component_metas", []);
330
- l(this, "component_count", 0);
331
- // --- Event channels ---
332
- // Parallel array indexed by EventID: each channel holds SoA columns + reader.
333
- l(this, "event_channels", []);
334
- l(this, "event_count", 0);
335
- // --- Archetype management ---
336
- l(this, "archetypes", []);
337
- // Hash-bucketed lookup: BitSet.hash() → ArchetypeID[] for deduplication
338
- l(this, "archetype_map", /* @__PURE__ */ new Map());
339
- l(this, "next_archetype_id", 0);
340
- // Inverted index: ComponentID → set of ArchetypeIDs containing that component.
341
- // Used by get_matching_archetypes to start from the smallest set.
342
- l(this, "component_index", /* @__PURE__ */ new Map());
343
- // Registered queries: the Store pushes newly-created archetypes into matching
344
- // query result arrays, so queries are always up-to-date.
345
- l(this, "registered_queries", []);
346
- l(this, "empty_archetype_id");
347
- // entity_index → ArchetypeID (UNASSIGNED = not in any archetype)
348
- l(this, "entity_archetype", []);
349
- // entity_index → row within its archetype (UNASSIGNED = no row)
350
- l(this, "entity_row", []);
351
- // --- Deferred operation buffers ---
352
- // Flat parallel arrays: pending_add_ids[i], pending_add_defs[i], pending_add_values[i]
353
- // describe one deferred add. No per-operation object allocation.
354
- l(this, "pending_destroy", []);
355
- l(this, "pending_add_ids", []);
356
- l(this, "pending_add_defs", []);
357
- l(this, "pending_add_values", []);
358
- l(this, "pending_remove_ids", []);
359
- l(this, "pending_remove_defs", []);
360
- this.empty_archetype_id = this.arch_get_or_create_from_mask(new T());
357
+ this.empty_archetype_id = this.arch_get_or_create_from_mask(new N());
361
358
  }
362
359
  // =======================================================
363
360
  // Archetype graph
364
361
  // =======================================================
365
362
  arch_get(t) {
366
363
  if (process.env.NODE_ENV !== "production" && (t < 0 || t >= this.archetypes.length))
367
- throw new g(
368
- u.ARCHETYPE_NOT_FOUND,
364
+ throw new u(
365
+ d.ARCHETYPE_NOT_FOUND,
369
366
  `Archetype with ID ${t} not found`
370
367
  );
371
368
  return this.archetypes[t];
@@ -381,25 +378,25 @@ class tt {
381
378
  if (this.archetypes[s[h]].mask.equals(t))
382
379
  return s[h];
383
380
  }
384
- const n = Z(this.next_archetype_id++), r = [];
381
+ const n = Q(this.next_archetype_id++), r = [];
385
382
  t.for_each((h) => {
386
- const i = h, c = this.component_metas[i];
383
+ const o = h, c = this.component_metas[o];
387
384
  c && c.field_names.length > 0 && r.push({
388
- component_id: i,
385
+ component_id: o,
389
386
  field_names: c.field_names,
390
387
  field_index: c.field_index
391
388
  });
392
389
  });
393
- const o = new H(n, t, r);
394
- this.archetypes.push(o), j(this.archetype_map, e, n), t.for_each((h) => {
395
- const i = h;
396
- let c = this.component_index.get(i);
397
- c || (c = /* @__PURE__ */ new Set(), this.component_index.set(i, c)), c.add(n);
390
+ const i = new K(n, t, r);
391
+ this.archetypes.push(i), F(this.archetype_map, e, n), t.for_each((h) => {
392
+ const o = h;
393
+ let c = this.component_index.get(o);
394
+ c || (c = /* @__PURE__ */ new Set(), this.component_index.set(o, c)), c.add(n);
398
395
  });
399
396
  const _ = this.registered_queries;
400
397
  for (let h = 0; h < _.length; h++) {
401
- const i = _[h];
402
- o.matches(i.include_mask) && (!i.exclude_mask || !o.mask.overlaps(i.exclude_mask)) && (!i.any_of_mask || o.mask.overlaps(i.any_of_mask)) && i.result.push(o);
398
+ const o = _[h];
399
+ i.matches(o.include_mask) && (!o.exclude_mask || !i.mask.overlaps(o.exclude_mask)) && (!o.any_of_mask || i.mask.overlaps(o.any_of_mask)) && o.result.push(i);
403
400
  }
404
401
  return n;
405
402
  }
@@ -408,7 +405,7 @@ class tt {
408
405
  const s = this.arch_get(t);
409
406
  if (s.mask.has(e)) return t;
410
407
  const n = s.get_edge(e);
411
- if ((n == null ? void 0 : n.add) != null) return n.add;
408
+ if (n?.add != null) return n.add;
412
409
  const r = this.arch_get_or_create_from_mask(
413
410
  s.mask.copy_with_set(e)
414
411
  );
@@ -419,7 +416,7 @@ class tt {
419
416
  const s = this.arch_get(t);
420
417
  if (!s.mask.has(e)) return t;
421
418
  const n = s.get_edge(e);
422
- if ((n == null ? void 0 : n.remove) != null) return n.remove;
419
+ if (n?.remove != null) return n.remove;
423
420
  const r = this.arch_get_or_create_from_mask(
424
421
  s.mask.copy_with_clear(e)
425
422
  );
@@ -441,29 +438,29 @@ class tt {
441
438
  create_entity() {
442
439
  let t, e;
443
440
  this.entity_free_indices.length > 0 ? (t = this.entity_free_indices.pop(), e = this.entity_generations[t]) : (t = this.entity_high_water++, this.entity_generations[t] = 0, e = 0), this.entity_alive_count++;
444
- const s = B(t, e);
445
- return this.entity_archetype[t] = this.empty_archetype_id, this.entity_row[t] = w, s;
441
+ const s = $(t, e);
442
+ return this.entity_archetype[t] = this.empty_archetype_id, this.entity_row[t] = m, s;
446
443
  }
447
444
  /** Immediately destroy an entity, removing it from its archetype. */
448
445
  destroy_entity(t) {
449
446
  if (!this.is_alive(t)) {
450
- if (process.env.NODE_ENV !== "production") throw new g(u.ENTITY_NOT_ALIVE);
447
+ if (process.env.NODE_ENV !== "production") throw new u(d.ENTITY_NOT_ALIVE);
451
448
  return;
452
449
  }
453
- const e = m(t), s = this.entity_row[e];
454
- if (s !== w) {
455
- const o = this.arch_get(this.entity_archetype[e]).remove_entity(s);
456
- o !== -1 && (this.entity_row[o] = s);
450
+ const e = y(t), s = this.entity_row[e];
451
+ if (s !== m) {
452
+ const i = this.arch_get(this.entity_archetype[e]).remove_entity(s);
453
+ i !== -1 && (this.entity_row[i] = s);
457
454
  }
458
- this.entity_archetype[e] = w, this.entity_row[e] = w;
459
- const n = R(t);
460
- if (process.env.NODE_ENV !== "production" && n >= k)
461
- throw new g(u.EID_MAX_GEN_OVERFLOW);
462
- this.entity_generations[e] = n + 1 & k, this.entity_free_indices.push(e), this.entity_alive_count--;
455
+ this.entity_archetype[e] = m, this.entity_row[e] = m;
456
+ const n = q(t);
457
+ if (process.env.NODE_ENV !== "production" && n >= D)
458
+ throw new u(d.EID_MAX_GEN_OVERFLOW);
459
+ this.entity_generations[e] = n + 1 & D, this.entity_free_indices.push(e), this.entity_alive_count--;
463
460
  }
464
461
  is_alive(t) {
465
- const e = m(t);
466
- return e < this.entity_high_water && this.entity_generations[e] === R(t);
462
+ const e = y(t);
463
+ return e < this.entity_high_water && this.entity_generations[e] === q(t);
467
464
  }
468
465
  get entity_count() {
469
466
  return this.entity_alive_count;
@@ -473,25 +470,25 @@ class tt {
473
470
  // =======================================================
474
471
  destroy_entity_deferred(t) {
475
472
  if (process.env.NODE_ENV !== "production" && !this.is_alive(t))
476
- throw new g(u.ENTITY_NOT_ALIVE);
473
+ throw new u(d.ENTITY_NOT_ALIVE);
477
474
  this.pending_destroy.push(t);
478
475
  }
479
476
  /** Flush all buffered entity destructions in batch. */
480
477
  flush_destroyed() {
481
478
  const t = this.pending_destroy;
482
479
  if (t.length === 0) return;
483
- const e = this.entity_archetype, s = this.entity_row, n = this.entity_generations, r = this.archetypes, o = this.entity_high_water;
480
+ const e = this.entity_archetype, s = this.entity_row, n = this.entity_generations, r = this.archetypes, i = this.entity_high_water;
484
481
  for (let _ = 0; _ < t.length; _++) {
485
- const h = t[_], i = h & S, c = h >> D;
486
- if (i >= o || n[i] !== c) continue;
487
- const d = s[i];
488
- if (d !== w) {
489
- const f = r[e[i]], p = f.has_columns ? f.remove_entity(d) : f.remove_entity_tag(d);
490
- p !== -1 && (s[p] = d);
482
+ const h = t[_], o = h & k, c = h >> I;
483
+ if (o >= i || n[o] !== c) continue;
484
+ const l = s[o];
485
+ if (l !== m) {
486
+ const p = r[e[o]], g = p.has_columns ? p.remove_entity(l) : p.remove_entity_tag(l);
487
+ g !== -1 && (s[g] = l);
491
488
  }
492
- if (e[i] = w, s[i] = w, process.env.NODE_ENV !== "production" && c >= k)
493
- throw new g(u.EID_MAX_GEN_OVERFLOW);
494
- n[i] = c + 1 & k, this.entity_free_indices.push(i), this.entity_alive_count--;
489
+ if (e[o] = m, s[o] = m, process.env.NODE_ENV !== "production" && c >= D)
490
+ throw new u(d.EID_MAX_GEN_OVERFLOW);
491
+ n[o] = c + 1 & D, this.entity_free_indices.push(o), this.entity_alive_count--;
495
492
  }
496
493
  t.length = 0;
497
494
  }
@@ -500,12 +497,12 @@ class tt {
500
497
  }
501
498
  add_component_deferred(t, e, s) {
502
499
  if (process.env.NODE_ENV !== "production" && !this.is_alive(t))
503
- throw new g(u.ENTITY_NOT_ALIVE);
504
- this.pending_add_ids.push(t), this.pending_add_defs.push(e), this.pending_add_values.push(s ?? M);
500
+ throw new u(d.ENTITY_NOT_ALIVE);
501
+ this.pending_add_ids.push(t), this.pending_add_defs.push(e), this.pending_add_values.push(s ?? V);
505
502
  }
506
503
  remove_component_deferred(t, e) {
507
504
  if (process.env.NODE_ENV !== "production" && !this.is_alive(t))
508
- throw new g(u.ENTITY_NOT_ALIVE);
505
+ throw new u(d.ENTITY_NOT_ALIVE);
509
506
  this.pending_remove_ids.push(t), this.pending_remove_defs.push(e);
510
507
  }
511
508
  flush_structural() {
@@ -513,37 +510,37 @@ class tt {
513
510
  }
514
511
  /** Batch-apply all deferred component additions. */
515
512
  _flush_adds() {
516
- const t = this.pending_add_ids, e = this.pending_add_defs, s = this.pending_add_values, n = t.length, r = this.entity_archetype, o = this.entity_row, _ = this.entity_generations, h = this.archetypes, i = this.component_metas, c = this.entity_high_water;
517
- for (let d = 0; d < n; d++) {
518
- const f = t[d], p = f & S, v = f >> D;
519
- if (p >= c || _[p] !== v) continue;
520
- const O = r[p], E = e[d], y = h[O];
521
- if (y.mask.has(E)) {
522
- i[E].field_names.length > 0 && y.write_fields(o[p], E, s[d]);
513
+ const t = this.pending_add_ids, e = this.pending_add_defs, s = this.pending_add_values, n = t.length, r = this.entity_archetype, i = this.entity_row, _ = this.entity_generations, h = this.archetypes, o = this.component_metas, c = this.entity_high_water;
514
+ for (let l = 0; l < n; l++) {
515
+ const p = t[l], g = p & k, w = p >> I;
516
+ if (g >= c || _[g] !== w) continue;
517
+ const T = r[g], v = e[l], f = h[T];
518
+ if (f.mask.has(v)) {
519
+ o[v].field_names.length > 0 && f.write_fields(i[g], v, s[l]);
523
520
  continue;
524
521
  }
525
- const A = this.arch_resolve_add(O, E), N = h[A], I = o[p], x = !N.has_columns && !y.has_columns, V = x ? N.add_entity_tag(f) : N.add_entity(f);
526
- if (I !== w) {
527
- x || N.copy_shared_from(y, I, V);
528
- const q = x ? y.remove_entity_tag(I) : y.remove_entity(I);
529
- q !== -1 && (o[q] = I);
522
+ const O = this.arch_resolve_add(T, v), E = h[O], x = i[g], A = !E.has_columns && !f.has_columns, S = A ? E.add_entity_tag(p) : E.add_entity(p);
523
+ if (x !== m) {
524
+ A || E.copy_shared_from(f, x, S);
525
+ const U = A ? f.remove_entity_tag(x) : f.remove_entity(x);
526
+ U !== -1 && (i[U] = x);
530
527
  }
531
- i[E].field_names.length > 0 && N.write_fields(V, E, s[d]), r[p] = A, o[p] = V;
528
+ o[v].field_names.length > 0 && E.write_fields(S, v, s[l]), r[g] = O, i[g] = S;
532
529
  }
533
530
  t.length = 0, e.length = 0, s.length = 0;
534
531
  }
535
532
  /** Batch-apply all deferred component removals. */
536
533
  _flush_removes() {
537
- const t = this.pending_remove_ids, e = this.pending_remove_defs, s = t.length, n = this.entity_archetype, r = this.entity_row, o = this.entity_generations, _ = this.archetypes, h = this.entity_high_water;
538
- for (let i = 0; i < s; i++) {
539
- const c = t[i], d = c & S, f = c >> D;
540
- if (d >= h || o[d] !== f) continue;
541
- const p = n[d], v = e[i], O = _[p];
542
- if (!O.mask.has(v)) continue;
543
- const E = this.arch_resolve_remove(p, v), y = _[E], A = r[d], N = !y.has_columns && !O.has_columns, I = N ? y.add_entity_tag(c) : y.add_entity(c);
544
- N || y.copy_shared_from(O, A, I);
545
- const x = N ? O.remove_entity_tag(A) : O.remove_entity(A);
546
- x !== -1 && (r[x] = A), n[d] = E, r[d] = I;
534
+ const t = this.pending_remove_ids, e = this.pending_remove_defs, s = t.length, n = this.entity_archetype, r = this.entity_row, i = this.entity_generations, _ = this.archetypes, h = this.entity_high_water;
535
+ for (let o = 0; o < s; o++) {
536
+ const c = t[o], l = c & k, p = c >> I;
537
+ if (l >= h || i[l] !== p) continue;
538
+ const g = n[l], w = e[o], T = _[g];
539
+ if (!T.mask.has(w)) continue;
540
+ const v = this.arch_resolve_remove(g, w), f = _[v], O = r[l], E = !f.has_columns && !T.has_columns, x = E ? f.add_entity_tag(c) : f.add_entity(c);
541
+ E || f.copy_shared_from(T, O, x);
542
+ const A = E ? T.remove_entity_tag(O) : T.remove_entity(O);
543
+ A !== -1 && (r[A] = O), n[l] = v, r[l] = x;
547
544
  }
548
545
  t.length = 0, e.length = 0;
549
546
  }
@@ -554,19 +551,19 @@ class tt {
554
551
  // Component registration
555
552
  // =======================================================
556
553
  register_component(t) {
557
- const e = Q(this.component_count++), s = t, n = /* @__PURE__ */ Object.create(null);
554
+ const e = z(this.component_count++), s = t, n = /* @__PURE__ */ Object.create(null);
558
555
  for (let r = 0; r < s.length; r++)
559
556
  n[s[r]] = r;
560
557
  return this.component_metas.push({ field_names: s, field_index: n }), e;
561
558
  }
562
559
  add_component(t, e, s) {
563
560
  if (!this.is_alive(t)) {
564
- if (process.env.NODE_ENV !== "production") throw new g(u.ENTITY_NOT_ALIVE);
561
+ if (process.env.NODE_ENV !== "production") throw new u(d.ENTITY_NOT_ALIVE);
565
562
  return;
566
563
  }
567
- const n = m(t), r = this.entity_archetype[n], o = this.arch_get(r);
568
- if (o.has_component(e)) {
569
- o.write_fields(
564
+ const n = y(t), r = this.entity_archetype[n], i = this.arch_get(r);
565
+ if (i.has_component(e)) {
566
+ i.write_fields(
570
567
  this.entity_row[n],
571
568
  e,
572
569
  s
@@ -576,11 +573,11 @@ class tt {
576
573
  const _ = this.arch_resolve_add(
577
574
  r,
578
575
  e
579
- ), h = this.arch_get(_), i = this.entity_row[n], c = h.add_entity(t);
580
- if (i !== w) {
581
- h.copy_shared_from(o, i, c);
582
- const d = o.remove_entity(i);
583
- d !== -1 && (this.entity_row[d] = i);
576
+ ), h = this.arch_get(_), o = this.entity_row[n], c = h.add_entity(t);
577
+ if (o !== m) {
578
+ h.copy_shared_from(i, o, c);
579
+ const l = i.remove_entity(o);
580
+ l !== -1 && (this.entity_row[l] = o);
584
581
  }
585
582
  h.write_fields(
586
583
  c,
@@ -591,80 +588,80 @@ class tt {
591
588
  /** Add multiple components in one transition (resolves final archetype, then moves once). */
592
589
  add_components(t, e) {
593
590
  if (!this.is_alive(t)) {
594
- if (process.env.NODE_ENV !== "production") throw new g(u.ENTITY_NOT_ALIVE);
591
+ if (process.env.NODE_ENV !== "production") throw new u(d.ENTITY_NOT_ALIVE);
595
592
  return;
596
593
  }
597
- const s = m(t), n = this.entity_archetype[s];
594
+ const s = y(t), n = this.entity_archetype[s];
598
595
  let r = n;
599
- for (let o = 0; o < e.length; o++)
596
+ for (let i = 0; i < e.length; i++)
600
597
  r = this.arch_resolve_add(
601
598
  r,
602
- e[o].def
599
+ e[i].def
603
600
  );
604
601
  if (r !== n) {
605
- const o = this.arch_get(n), _ = this.arch_get(r), h = this.entity_row[s], i = _.add_entity(t);
606
- if (h !== w) {
607
- _.copy_shared_from(o, h, i);
608
- const c = o.remove_entity(h);
602
+ const i = this.arch_get(n), _ = this.arch_get(r), h = this.entity_row[s], o = _.add_entity(t);
603
+ if (h !== m) {
604
+ _.copy_shared_from(i, h, o);
605
+ const c = i.remove_entity(h);
609
606
  c !== -1 && (this.entity_row[c] = h);
610
607
  }
611
608
  for (let c = 0; c < e.length; c++)
612
609
  _.write_fields(
613
- i,
610
+ o,
614
611
  e[c].def,
615
- e[c].values ?? M
612
+ e[c].values ?? V
616
613
  );
617
- this.entity_archetype[s] = r, this.entity_row[s] = i;
614
+ this.entity_archetype[s] = r, this.entity_row[s] = o;
618
615
  } else {
619
- const o = this.arch_get(n), _ = this.entity_row[s];
616
+ const i = this.arch_get(n), _ = this.entity_row[s];
620
617
  for (let h = 0; h < e.length; h++)
621
- o.write_fields(
618
+ i.write_fields(
622
619
  _,
623
620
  e[h].def,
624
- e[h].values ?? M
621
+ e[h].values ?? V
625
622
  );
626
623
  }
627
624
  }
628
625
  remove_component(t, e) {
629
626
  if (!this.is_alive(t)) {
630
- if (process.env.NODE_ENV !== "production") throw new g(u.ENTITY_NOT_ALIVE);
627
+ if (process.env.NODE_ENV !== "production") throw new u(d.ENTITY_NOT_ALIVE);
631
628
  return;
632
629
  }
633
- const s = m(t), n = this.entity_archetype[s], r = this.arch_get(n);
630
+ const s = y(t), n = this.entity_archetype[s], r = this.arch_get(n);
634
631
  if (!r.has_component(e)) return;
635
- const o = this.arch_resolve_remove(
632
+ const i = this.arch_resolve_remove(
636
633
  n,
637
634
  e
638
- ), _ = this.arch_get(o), h = this.entity_row[s], i = _.add_entity(t);
639
- _.copy_shared_from(r, h, i);
635
+ ), _ = this.arch_get(i), h = this.entity_row[s], o = _.add_entity(t);
636
+ _.copy_shared_from(r, h, o);
640
637
  const c = r.remove_entity(h);
641
- c !== -1 && (this.entity_row[c] = h), this.entity_archetype[s] = o, this.entity_row[s] = i;
638
+ c !== -1 && (this.entity_row[c] = h), this.entity_archetype[s] = i, this.entity_row[s] = o;
642
639
  }
643
640
  /** Remove multiple components in one transition (resolves final archetype, then moves once). */
644
641
  remove_components(t, e) {
645
642
  if (!this.is_alive(t)) {
646
- if (process.env.NODE_ENV !== "production") throw new g(u.ENTITY_NOT_ALIVE);
643
+ if (process.env.NODE_ENV !== "production") throw new u(d.ENTITY_NOT_ALIVE);
647
644
  return;
648
645
  }
649
- const s = m(t), n = this.entity_archetype[s];
646
+ const s = y(t), n = this.entity_archetype[s];
650
647
  let r = n;
651
- for (let d = 0; d < e.length; d++)
648
+ for (let l = 0; l < e.length; l++)
652
649
  r = this.arch_resolve_remove(
653
650
  r,
654
- e[d]
651
+ e[l]
655
652
  );
656
653
  if (r === n) return;
657
- const o = this.arch_get(n), _ = this.arch_get(r), h = this.entity_row[s], i = _.add_entity(t);
658
- _.copy_shared_from(o, h, i);
659
- const c = o.remove_entity(h);
660
- c !== -1 && (this.entity_row[c] = h), this.entity_archetype[s] = r, this.entity_row[s] = i;
654
+ const i = this.arch_get(n), _ = this.arch_get(r), h = this.entity_row[s], o = _.add_entity(t);
655
+ _.copy_shared_from(i, h, o);
656
+ const c = i.remove_entity(h);
657
+ c !== -1 && (this.entity_row[c] = h), this.entity_archetype[s] = r, this.entity_row[s] = o;
661
658
  }
662
659
  has_component(t, e) {
663
660
  if (!this.is_alive(t)) {
664
- if (process.env.NODE_ENV !== "production") throw new g(u.ENTITY_NOT_ALIVE);
661
+ if (process.env.NODE_ENV !== "production") throw new u(d.ENTITY_NOT_ALIVE);
665
662
  return !1;
666
663
  }
667
- const s = m(t);
664
+ const s = y(t);
668
665
  return this.arch_get(
669
666
  this.entity_archetype[s]
670
667
  ).has_component(e);
@@ -674,11 +671,11 @@ class tt {
674
671
  // =======================================================
675
672
  get_entity_archetype(t) {
676
673
  return this.arch_get(
677
- this.entity_archetype[m(t)]
674
+ this.entity_archetype[y(t)]
678
675
  );
679
676
  }
680
677
  get_entity_row(t) {
681
- return this.entity_row[m(t)];
678
+ return this.entity_row[y(t)];
682
679
  }
683
680
  // =======================================================
684
681
  // Query support
@@ -691,36 +688,36 @@ class tt {
691
688
  get_matching_archetypes(t, e, s) {
692
689
  const n = t._words;
693
690
  let r = !1;
694
- for (let i = 0; i < n.length; i++)
695
- if (n[i] !== 0) {
691
+ for (let o = 0; o < n.length; o++)
692
+ if (n[o] !== 0) {
696
693
  r = !0;
697
694
  break;
698
695
  }
699
696
  if (!r)
700
697
  return this.archetypes.filter(
701
- (i) => (!e || !i.mask.overlaps(e)) && (!s || i.mask.overlaps(s))
698
+ (o) => (!e || !o.mask.overlaps(e)) && (!s || o.mask.overlaps(s))
702
699
  );
703
- let o, _ = !1;
704
- for (let i = 0; i < n.length; i++) {
705
- let c = n[i];
700
+ let i, _ = !1;
701
+ for (let o = 0; o < n.length; o++) {
702
+ let c = n[o];
706
703
  if (c === 0) continue;
707
- const d = i << 5;
704
+ const l = o << 5;
708
705
  for (; c !== 0; ) {
709
- const f = c & -c >>> 0, p = d + (31 - Math.clz32(f));
710
- c ^= f;
711
- const v = this.component_index.get(p);
712
- if (!v || v.size === 0) {
706
+ const p = c & -c >>> 0, g = l + (31 - Math.clz32(p));
707
+ c ^= p;
708
+ const w = this.component_index.get(g);
709
+ if (!w || w.size === 0) {
713
710
  _ = !0;
714
711
  break;
715
712
  }
716
- (!o || v.size < o.size) && (o = v);
713
+ (!i || w.size < i.size) && (i = w);
717
714
  }
718
715
  if (_) break;
719
716
  }
720
- if (_ || !o) return [];
717
+ if (_ || !i) return [];
721
718
  const h = [];
722
- for (const i of o) {
723
- const c = this.arch_get(i);
719
+ for (const o of i) {
720
+ const c = this.arch_get(o);
724
721
  c.matches(t) && (!e || !c.mask.overlaps(e)) && (!s || c.mask.overlaps(s)) && h.push(c);
725
722
  }
726
723
  return h;
@@ -749,7 +746,7 @@ class tt {
749
746
  // Event channels
750
747
  // =======================================================
751
748
  register_event(t) {
752
- const e = K(this.event_count++), s = new J(t);
749
+ const e = W(this.event_count++), s = new B(t);
753
750
  return this.event_channels.push(s), e;
754
751
  }
755
752
  emit_event(t, e) {
@@ -767,44 +764,45 @@ class tt {
767
764
  t[e].clear();
768
765
  }
769
766
  }
770
- var et = /* @__PURE__ */ ((a) => (a.PRE_STARTUP = "PRE_STARTUP", a.STARTUP = "STARTUP", a.POST_STARTUP = "POST_STARTUP", a.PRE_UPDATE = "PRE_UPDATE", a.UPDATE = "UPDATE", a.POST_UPDATE = "POST_UPDATE", a))(et || {});
771
- const L = [
767
+ var Z = /* @__PURE__ */ ((a) => (a.PRE_STARTUP = "PRE_STARTUP", a.STARTUP = "STARTUP", a.POST_STARTUP = "POST_STARTUP", a.FIXED_UPDATE = "FIXED_UPDATE", a.PRE_UPDATE = "PRE_UPDATE", a.UPDATE = "UPDATE", a.POST_UPDATE = "POST_UPDATE", a))(Z || {});
768
+ const M = [
772
769
  "PRE_STARTUP",
773
770
  "STARTUP",
774
771
  "POST_STARTUP"
775
772
  /* POST_STARTUP */
776
- ], U = [
773
+ ], L = [
777
774
  "PRE_UPDATE",
778
775
  "UPDATE",
779
776
  "POST_UPDATE"
780
777
  /* POST_UPDATE */
781
778
  ];
782
- class st {
779
+ class H {
780
+ label_systems = /* @__PURE__ */ new Map();
781
+ sorted_cache = /* @__PURE__ */ new Map();
782
+ system_index = /* @__PURE__ */ new Map();
783
+ next_insertion_order = 0;
783
784
  constructor() {
784
- l(this, "label_systems", /* @__PURE__ */ new Map());
785
- l(this, "sorted_cache", /* @__PURE__ */ new Map());
786
- l(this, "system_index", /* @__PURE__ */ new Map());
787
- l(this, "next_insertion_order", 0);
785
+ for (let t = 0; t < M.length; t++)
786
+ this.label_systems.set(M[t], []);
787
+ this.label_systems.set("FIXED_UPDATE", []);
788
788
  for (let t = 0; t < L.length; t++)
789
789
  this.label_systems.set(L[t], []);
790
- for (let t = 0; t < U.length; t++)
791
- this.label_systems.set(U[t], []);
792
790
  }
793
791
  add_systems(t, ...e) {
794
792
  for (const s of e) {
795
793
  const n = "system" in s ? s.system : s, r = "system" in s ? s.ordering : void 0;
796
794
  if (process.env.NODE_ENV !== "production" && this.system_index.has(n))
797
- throw new g(
798
- u.DUPLICATE_SYSTEM,
795
+ throw new u(
796
+ d.DUPLICATE_SYSTEM,
799
797
  `System ${n.id} is already scheduled`
800
798
  );
801
- const o = {
799
+ const i = {
802
800
  descriptor: n,
803
801
  insertion_order: this.next_insertion_order++,
804
- before: new Set((r == null ? void 0 : r.before) ?? []),
805
- after: new Set((r == null ? void 0 : r.after) ?? [])
802
+ before: new Set(r?.before ?? []),
803
+ after: new Set(r?.after ?? [])
806
804
  };
807
- this.label_systems.get(t).push(o), this.system_index.set(n, t), this.sorted_cache.delete(t);
805
+ this.label_systems.get(t).push(i), this.system_index.set(n, t), this.sorted_cache.delete(t);
808
806
  }
809
807
  }
810
808
  remove_system(t) {
@@ -814,19 +812,28 @@ class st {
814
812
  if (n !== -1) {
815
813
  const r = s.length - 1;
816
814
  n !== r && (s[n] = s[r]), s.pop();
817
- for (const o of s)
818
- o.before.delete(t), o.after.delete(t);
815
+ for (const i of s)
816
+ i.before.delete(t), i.after.delete(t);
819
817
  }
820
818
  this.system_index.delete(t), this.sorted_cache.delete(e);
821
819
  }
822
820
  run_startup(t) {
823
- for (const e of L)
821
+ for (const e of M)
824
822
  this.run_label(e, t, 0);
825
823
  }
826
824
  run_update(t, e) {
827
- for (const s of U)
825
+ for (const s of L)
828
826
  this.run_label(s, t, e);
829
827
  }
828
+ run_fixed_update(t, e) {
829
+ this.run_label("FIXED_UPDATE", t, e);
830
+ }
831
+ has_fixed_systems() {
832
+ return this.label_systems.get(
833
+ "FIXED_UPDATE"
834
+ /* FIXED_UPDATE */
835
+ ).length > 0;
836
+ }
830
837
  get_all_systems() {
831
838
  const t = [];
832
839
  for (const e of this.label_systems.values())
@@ -860,52 +867,52 @@ class st {
860
867
  */
861
868
  topological_sort(t, e) {
862
869
  if (t.length === 0) return [];
863
- const s = /* @__PURE__ */ new Map(), n = /* @__PURE__ */ new Map(), r = /* @__PURE__ */ new Map(), o = /* @__PURE__ */ new Set();
864
- for (const i of t)
865
- s.set(i.descriptor, /* @__PURE__ */ new Set()), n.set(i.descriptor, 0), r.set(i.descriptor, i.insertion_order), o.add(i.descriptor);
866
- for (const i of t) {
867
- for (const c of i.before)
868
- o.has(c) && (s.get(i.descriptor).add(c), n.set(c, n.get(c) + 1));
869
- for (const c of i.after)
870
- o.has(c) && (s.get(c).add(i.descriptor), n.set(i.descriptor, n.get(i.descriptor) + 1));
870
+ const s = /* @__PURE__ */ new Map(), n = /* @__PURE__ */ new Map(), r = /* @__PURE__ */ new Map(), i = /* @__PURE__ */ new Set();
871
+ for (const o of t)
872
+ s.set(o.descriptor, /* @__PURE__ */ new Set()), n.set(o.descriptor, 0), r.set(o.descriptor, o.insertion_order), i.add(o.descriptor);
873
+ for (const o of t) {
874
+ for (const c of o.before)
875
+ i.has(c) && (s.get(o.descriptor).add(c), n.set(c, n.get(c) + 1));
876
+ for (const c of o.after)
877
+ i.has(c) && (s.get(c).add(o.descriptor), n.set(o.descriptor, n.get(o.descriptor) + 1));
871
878
  }
872
879
  let _ = [];
873
- for (const i of t)
874
- n.get(i.descriptor) === 0 && _.push(i.descriptor);
875
- _.sort((i, c) => r.get(c) - r.get(i));
880
+ for (const o of t)
881
+ n.get(o.descriptor) === 0 && _.push(o.descriptor);
882
+ _.sort((o, c) => r.get(c) - r.get(o));
876
883
  const h = [];
877
884
  for (; _.length > 0; ) {
878
- const i = _.pop();
879
- h.push(i);
880
- for (const c of s.get(i)) {
881
- const d = n.get(c) - 1;
882
- n.set(c, d), d === 0 && _.push(c);
885
+ const o = _.pop();
886
+ h.push(o);
887
+ for (const c of s.get(o)) {
888
+ const l = n.get(c) - 1;
889
+ n.set(c, l), l === 0 && _.push(c);
883
890
  }
884
- _.sort((c, d) => r.get(d) - r.get(c));
891
+ _.sort((c, l) => r.get(l) - r.get(c));
885
892
  }
886
893
  if (h.length !== t.length) {
887
- const i = new Set(h), c = t.filter((d) => !i.has(d.descriptor)).map((d) => `system_${d.descriptor.id}`);
888
- throw new g(
889
- u.CIRCULAR_SYSTEM_DEPENDENCY,
894
+ const o = new Set(h), c = t.filter((l) => !o.has(l.descriptor)).map((l) => `system_${l.descriptor.id}`);
895
+ throw new u(
896
+ d.CIRCULAR_SYSTEM_DEPENDENCY,
890
897
  `Circular system dependency detected in ${e}: [${c.join(", ")}]`
891
898
  );
892
899
  }
893
900
  return h;
894
901
  }
895
902
  }
896
- const nt = Object.freeze(/* @__PURE__ */ Object.create(null));
897
- class rt {
898
- constructor(t, e, s, n, r, o) {
899
- l(this, "_archetypes");
900
- l(this, "_defs");
901
- l(this, "_resolver");
902
- l(this, "_include");
903
- l(this, "_exclude");
904
- l(this, "_any_of");
905
- // Pre-allocated args buffer for each() — avoids allocating a new array per
906
- // archetype. Holds [columnGroup0, columnGroup1, ..., entityCount].
907
- l(this, "_args_buf");
908
- this._archetypes = t, this._defs = e, this._resolver = s, this._include = n, this._exclude = r, this._any_of = o, this._args_buf = new Array(e.length + 1);
903
+ const tt = Object.freeze(/* @__PURE__ */ Object.create(null));
904
+ class et {
905
+ _archetypes;
906
+ _defs;
907
+ _resolver;
908
+ _include;
909
+ _exclude;
910
+ _any_of;
911
+ // Pre-allocated args buffer for each() — avoids allocating a new array per
912
+ // archetype. Holds [columnGroup0, columnGroup1, ..., entityCount].
913
+ _args_buf;
914
+ constructor(t, e, s, n, r, i) {
915
+ this._archetypes = t, this._defs = e, this._resolver = s, this._include = n, this._exclude = r, this._any_of = i, this._args_buf = new Array(e.length + 1);
909
916
  }
910
917
  /** Number of matching archetypes (including empty ones). */
911
918
  get length() {
@@ -935,10 +942,10 @@ class rt {
935
942
  each(t) {
936
943
  const e = this._archetypes, s = this._defs, n = this._args_buf;
937
944
  for (let r = 0; r < e.length; r++) {
938
- const o = e[r], _ = o.entity_count;
945
+ const i = e[r], _ = i.entity_count;
939
946
  if (_ !== 0) {
940
947
  for (let h = 0; h < s.length; h++)
941
- n[h] = o.get_column_group(s[h]);
948
+ n[h] = i.get_column_group(s[h]);
942
949
  n[s.length] = _, t.apply(null, n);
943
950
  }
944
951
  }
@@ -957,7 +964,7 @@ class rt {
957
964
  }
958
965
  /** Exclude archetypes that have any of these components. */
959
966
  not(...t) {
960
- const e = this._exclude ? this._exclude.copy() : new T();
967
+ const e = this._exclude ? this._exclude.copy() : new N();
961
968
  for (let s = 0; s < t.length; s++) e.set(t[s]);
962
969
  return this._resolver._resolve_query(
963
970
  this._include,
@@ -968,7 +975,7 @@ class rt {
968
975
  }
969
976
  /** Require at least one of these components. */
970
977
  or(...t) {
971
- const e = this._any_of ? this._any_of.copy() : new T();
978
+ const e = this._any_of ? this._any_of.copy() : new N();
972
979
  for (let s = 0; s < t.length; s++) e.set(t[s]);
973
980
  return this._resolver._resolve_query(
974
981
  this._include,
@@ -978,19 +985,19 @@ class rt {
978
985
  );
979
986
  }
980
987
  }
981
- class ot {
988
+ class st {
982
989
  constructor(t) {
983
990
  this._resolver = t;
984
991
  }
985
992
  every(...t) {
986
- const e = new T();
993
+ const e = new N();
987
994
  for (let s = 0; s < t.length; s++) e.set(t[s]);
988
995
  return this._resolver._resolve_query(e, null, null, t);
989
996
  }
990
997
  }
991
- class it {
998
+ class nt {
999
+ store;
992
1000
  constructor(t) {
993
- l(this, "store");
994
1001
  this.store = t;
995
1002
  }
996
1003
  create_entity() {
@@ -1001,8 +1008,8 @@ class it {
1001
1008
  return n.read_field(r, t, s);
1002
1009
  }
1003
1010
  set_field(t, e, s, n) {
1004
- const r = this.store.get_entity_archetype(e), o = this.store.get_entity_row(e), _ = r.get_column(t, s);
1005
- _[o] = n;
1011
+ const r = this.store.get_entity_archetype(e), i = this.store.get_entity_row(e), _ = r.get_column(t, s);
1012
+ _[i] = n;
1006
1013
  }
1007
1014
  /** Buffer an entity for deferred destruction (applied at phase flush). */
1008
1015
  destroy_entity(t) {
@@ -1012,7 +1019,7 @@ class it {
1012
1019
  this.store.flush_destroyed();
1013
1020
  }
1014
1021
  add_component(t, e, s) {
1015
- return this.store.add_component_deferred(t, e, s ?? nt), this;
1022
+ return this.store.add_component_deferred(t, e, s ?? tt), this;
1016
1023
  }
1017
1024
  remove_component(t, e) {
1018
1025
  return this.store.remove_component_deferred(t, e), this;
@@ -1028,24 +1035,37 @@ class it {
1028
1035
  return this.store.get_event_reader(t);
1029
1036
  }
1030
1037
  }
1031
- const _t = (a) => b(
1038
+ const rt = (a) => b(
1032
1039
  a,
1033
1040
  P,
1034
1041
  "SystemID must be a non-negative integer"
1035
- ), ct = Object.freeze(/* @__PURE__ */ Object.create(null));
1036
- class at {
1037
- constructor() {
1038
- l(this, "store");
1039
- l(this, "schedule");
1040
- l(this, "ctx");
1041
- l(this, "systems", /* @__PURE__ */ new Set());
1042
- l(this, "next_system_id", 0);
1043
- // Query deduplication: hash(include, exclude, any_of) → bucket of cache entries.
1044
- // Multiple queries can share the same hash (collision), so each bucket is an array.
1045
- l(this, "query_cache", /* @__PURE__ */ new Map());
1046
- // Reusable BitSet for building query masks avoids allocation per query() call
1047
- l(this, "scratch_mask", new T());
1048
- this.store = new tt(), this.schedule = new st(), this.ctx = new it(this.store);
1042
+ ), it = Object.freeze(/* @__PURE__ */ Object.create(null));
1043
+ class ot {
1044
+ store;
1045
+ schedule;
1046
+ ctx;
1047
+ systems = /* @__PURE__ */ new Set();
1048
+ next_system_id = 0;
1049
+ // Fixed timestep accumulator
1050
+ _fixed_timestep;
1051
+ _accumulator = 0;
1052
+ _max_fixed_steps;
1053
+ // Query deduplication: hash(include, exclude, any_of) bucket of cache entries.
1054
+ // Multiple queries can share the same hash (collision), so each bucket is an array.
1055
+ query_cache = /* @__PURE__ */ new Map();
1056
+ // Reusable BitSet for building query masks — avoids allocation per query() call
1057
+ scratch_mask = new N();
1058
+ constructor(t) {
1059
+ this.store = new J(), this.schedule = new H(), this.ctx = new nt(this.store), this._fixed_timestep = t?.fixed_timestep ?? 1 / 60, this._max_fixed_steps = t?.max_fixed_steps ?? 4;
1060
+ }
1061
+ get fixed_timestep() {
1062
+ return this._fixed_timestep;
1063
+ }
1064
+ set fixed_timestep(t) {
1065
+ this._fixed_timestep = t;
1066
+ }
1067
+ get fixed_alpha() {
1068
+ return this._accumulator / this._fixed_timestep;
1049
1069
  }
1050
1070
  register_component(t) {
1051
1071
  return this.store.register_component(t);
@@ -1072,7 +1092,7 @@ class at {
1072
1092
  return this.store.entity_count;
1073
1093
  }
1074
1094
  add_component(t, e, s) {
1075
- this.store.add_component(t, e, s ?? ct);
1095
+ this.store.add_component(t, e, s ?? it);
1076
1096
  }
1077
1097
  add_components(t, e) {
1078
1098
  this.store.add_components(t, e);
@@ -1102,32 +1122,32 @@ class at {
1102
1122
  }
1103
1123
  /** QueryResolver implementation — creates or retrieves a cached Query. */
1104
1124
  _resolve_query(t, e, s, n) {
1105
- const r = t.hash(), o = e ? e.hash() : 0, _ = s ? s.hash() : 0, h = r ^ Math.imul(o, 2654435769) ^ Math.imul(_, 1367130551) | 0, i = this._find_cached(h, t, e, s);
1106
- if (i !== void 0) return i.query;
1125
+ const r = t.hash(), i = e ? e.hash() : 0, _ = s ? s.hash() : 0, h = r ^ Math.imul(i, 2654435769) ^ Math.imul(_, 1367130551) | 0, o = this._find_cached(h, t, e, s);
1126
+ if (o !== void 0) return o.query;
1107
1127
  const c = this.store.register_query(
1108
1128
  t,
1109
1129
  e ?? void 0,
1110
1130
  s ?? void 0
1111
- ), d = new rt(
1131
+ ), l = new et(
1112
1132
  c,
1113
1133
  n,
1114
1134
  this,
1115
1135
  t.copy(),
1116
- (e == null ? void 0 : e.copy()) ?? null,
1117
- (s == null ? void 0 : s.copy()) ?? null
1136
+ e?.copy() ?? null,
1137
+ s?.copy() ?? null
1118
1138
  );
1119
- return j(this.query_cache, h, {
1139
+ return F(this.query_cache, h, {
1120
1140
  include_mask: t.copy(),
1121
- exclude_mask: (e == null ? void 0 : e.copy()) ?? null,
1122
- any_of_mask: (s == null ? void 0 : s.copy()) ?? null,
1123
- query: d
1124
- }), d;
1141
+ exclude_mask: e?.copy() ?? null,
1142
+ any_of_mask: s?.copy() ?? null,
1143
+ query: l
1144
+ }), l;
1125
1145
  }
1126
1146
  _find_cached(t, e, s, n) {
1127
1147
  const r = this.query_cache.get(t);
1128
1148
  if (r)
1129
- for (let o = 0; o < r.length; o++) {
1130
- const _ = r[o];
1149
+ for (let i = 0; i < r.length; i++) {
1150
+ const _ = r[i];
1131
1151
  if (!(!_.include_mask.equals(e) || !(s === null ? _.exclude_mask === null : _.exclude_mask !== null && _.exclude_mask.equals(s)) || !(n === null ? _.any_of_mask === null : _.any_of_mask !== null && _.any_of_mask.equals(n))))
1132
1152
  return _;
1133
1153
  }
@@ -1135,11 +1155,11 @@ class at {
1135
1155
  register_system(t, e) {
1136
1156
  let s;
1137
1157
  if (typeof t == "function") {
1138
- const o = e(new ot(this)), _ = this.ctx;
1139
- s = { fn: (h, i) => t(o, _, i) };
1158
+ const i = e(new st(this)), _ = this.ctx;
1159
+ s = { fn: (h, o) => t(i, _, o) };
1140
1160
  } else
1141
1161
  s = t;
1142
- const n = _t(this.next_system_id++), r = Object.freeze(
1162
+ const n = rt(this.next_system_id++), r = Object.freeze(
1143
1163
  Object.assign({ id: n }, s)
1144
1164
  );
1145
1165
  return this.systems.add(r), r;
@@ -1148,35 +1168,38 @@ class at {
1148
1168
  return this.schedule.add_systems(t, ...e), this;
1149
1169
  }
1150
1170
  remove_system(t) {
1151
- var e;
1152
- this.schedule.remove_system(t), (e = t.on_removed) == null || e.call(t), this.systems.delete(t);
1171
+ this.schedule.remove_system(t), t.on_removed?.(), this.systems.delete(t);
1153
1172
  }
1154
1173
  get system_count() {
1155
1174
  return this.systems.size;
1156
1175
  }
1157
1176
  startup() {
1158
- var t;
1159
- for (const e of this.systems.values())
1160
- (t = e.on_added) == null || t.call(e, this.store);
1177
+ for (const t of this.systems.values())
1178
+ t.on_added?.(this.store);
1161
1179
  this.schedule.run_startup(this.ctx);
1162
1180
  }
1163
1181
  update(t) {
1164
- this.store.clear_events(), this.schedule.run_update(this.ctx, t);
1182
+ if (this.store.clear_events(), this.schedule.has_fixed_systems()) {
1183
+ this._accumulator += t;
1184
+ const e = this._max_fixed_steps * this._fixed_timestep;
1185
+ for (this._accumulator > e && (this._accumulator = e); this._accumulator >= this._fixed_timestep; )
1186
+ this.schedule.run_fixed_update(this.ctx, this._fixed_timestep), this._accumulator -= this._fixed_timestep;
1187
+ }
1188
+ this.schedule.run_update(this.ctx, t);
1165
1189
  }
1166
1190
  flush() {
1167
1191
  this.ctx.flush();
1168
1192
  }
1169
1193
  dispose() {
1170
- var t, e;
1171
- for (const s of this.systems.values())
1172
- (t = s.dispose) == null || t.call(s), (e = s.on_removed) == null || e.call(s);
1194
+ for (const t of this.systems.values())
1195
+ t.dispose?.(), t.on_removed?.();
1173
1196
  this.systems.clear(), this.schedule.clear();
1174
1197
  }
1175
1198
  }
1176
1199
  export {
1177
- rt as Query,
1178
- ot as QueryBuilder,
1179
- et as SCHEDULE,
1180
- it as SystemContext,
1181
- at as World
1200
+ et as Query,
1201
+ st as QueryBuilder,
1202
+ Z as SCHEDULE,
1203
+ nt as SystemContext,
1204
+ ot as World
1182
1205
  };