kitchen-simulator 3.16.2-test-renderer-fix → 3.16.3-test-renderer-fix

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/lib/index.js CHANGED
@@ -29,18 +29,12 @@ function nextFrame() {
29
29
  return requestAnimationFrame(resolve);
30
30
  });
31
31
  }
32
- function sleep(ms) {
33
- return new Promise(function (resolve) {
34
- return setTimeout(resolve, ms);
35
- });
36
- }
37
32
 
38
33
  /**
39
34
  * Track GLTF/GLB network activity via XHR + fetch.
40
- * Returns { getInFlight, waitForIdle, uninstall }.
35
+ * Ref-counted global install so multiple instances don't clobber each other.
41
36
  */
42
37
  function installGltfTracker() {
43
- var _XHR$prototype, _XHR$prototype2;
44
38
  if (typeof window === 'undefined') {
45
39
  return {
46
40
  getInFlight: function getInFlight() {
@@ -66,15 +60,36 @@ function installGltfTracker() {
66
60
  uninstall: function uninstall() {}
67
61
  };
68
62
  }
69
- var inFlight = 0;
70
- var listeners = new Set();
63
+ var GLOBAL_KEY = '__kitchenSimulatorGltfTracker__';
64
+ if (!window[GLOBAL_KEY]) {
65
+ window[GLOBAL_KEY] = {
66
+ refCount: 0,
67
+ inFlight: 0,
68
+ listeners: new Set(),
69
+ installed: false,
70
+ originalFetch: null,
71
+ originalOpen: null,
72
+ originalSend: null
73
+ };
74
+ }
75
+ var g = window[GLOBAL_KEY];
76
+ var isGltfUrl = function isGltfUrl(url) {
77
+ try {
78
+ var _url$toString, _url$toString2;
79
+ var s = typeof url === 'string' ? url : (_url$toString = url === null || url === void 0 || (_url$toString2 = url.toString) === null || _url$toString2 === void 0 ? void 0 : _url$toString2.call(url)) !== null && _url$toString !== void 0 ? _url$toString : '';
80
+ var u = s.toLowerCase();
81
+ return u.includes('.gltf') || u.includes('.glb');
82
+ } catch (_unused) {
83
+ return false;
84
+ }
85
+ };
71
86
  var notify = function notify() {
72
- var _iterator = _createForOfIteratorHelper(listeners),
87
+ var _iterator = _createForOfIteratorHelper(g.listeners),
73
88
  _step;
74
89
  try {
75
90
  for (_iterator.s(); !(_step = _iterator.n()).done;) {
76
91
  var fn = _step.value;
77
- fn(inFlight);
92
+ fn(g.inFlight);
78
93
  }
79
94
  } catch (err) {
80
95
  _iterator.e(err);
@@ -82,150 +97,199 @@ function installGltfTracker() {
82
97
  _iterator.f();
83
98
  }
84
99
  };
85
- var isGltfUrl = function isGltfUrl(url) {
86
- try {
87
- var _url$toString, _url$toString2;
88
- var s = typeof url === 'string' ? url : (_url$toString = url === null || url === void 0 || (_url$toString2 = url.toString) === null || _url$toString2 === void 0 ? void 0 : _url$toString2.call(url)) !== null && _url$toString !== void 0 ? _url$toString : '';
89
- var u = s.toLowerCase();
90
- return u.includes('.gltf') || u.includes('.glb');
91
- } catch (_unused) {
92
- return false;
93
- }
100
+ var subscribe = function subscribe(fn) {
101
+ g.listeners.add(fn);
102
+ fn(g.inFlight); // sync emit
103
+ return function () {
104
+ return g.listeners["delete"](fn);
105
+ };
94
106
  };
107
+ var installIfNeeded = function installIfNeeded() {
108
+ var _XHR$prototype, _XHR$prototype2;
109
+ if (g.installed) return;
95
110
 
96
- // ---- XHR hook ----
97
- var XHR = window.XMLHttpRequest;
98
- var originalOpen = null;
99
- var originalSend = null;
100
- if (XHR !== null && XHR !== void 0 && (_XHR$prototype = XHR.prototype) !== null && _XHR$prototype !== void 0 && _XHR$prototype.open && XHR !== null && XHR !== void 0 && (_XHR$prototype2 = XHR.prototype) !== null && _XHR$prototype2 !== void 0 && _XHR$prototype2.send) {
101
- originalOpen = XHR.prototype.open;
102
- originalSend = XHR.prototype.send;
103
- XHR.prototype.open = function (method, url) {
104
- var _originalOpen;
105
- this.__isGltfRequest = isGltfUrl(url);
106
- for (var _len = arguments.length, rest = new Array(_len > 2 ? _len - 2 : 0), _key = 2; _key < _len; _key++) {
107
- rest[_key - 2] = arguments[_key];
108
- }
109
- return (_originalOpen = originalOpen).call.apply(_originalOpen, [this, method, url].concat(rest));
110
- };
111
- XHR.prototype.send = function () {
112
- var _this = this;
113
- if (this.__isGltfRequest) {
114
- inFlight += 1;
115
- notify();
116
- var _done = function done() {
117
- inFlight -= 1;
118
- if (inFlight < 0) inFlight = 0;
111
+ // ---- XHR hook ----
112
+ var XHR = window.XMLHttpRequest;
113
+ if (XHR !== null && XHR !== void 0 && (_XHR$prototype = XHR.prototype) !== null && _XHR$prototype !== void 0 && _XHR$prototype.open && XHR !== null && XHR !== void 0 && (_XHR$prototype2 = XHR.prototype) !== null && _XHR$prototype2 !== void 0 && _XHR$prototype2.send) {
114
+ g.originalOpen = XHR.prototype.open;
115
+ g.originalSend = XHR.prototype.send;
116
+ XHR.prototype.open = function (method, url) {
117
+ var _g$originalOpen;
118
+ this.__isGltfRequest = isGltfUrl(url);
119
+ for (var _len = arguments.length, rest = new Array(_len > 2 ? _len - 2 : 0), _key = 2; _key < _len; _key++) {
120
+ rest[_key - 2] = arguments[_key];
121
+ }
122
+ return (_g$originalOpen = g.originalOpen).call.apply(_g$originalOpen, [this, method, url].concat(rest));
123
+ };
124
+ XHR.prototype.send = function () {
125
+ var _this = this;
126
+ if (this.__isGltfRequest) {
127
+ g.inFlight += 1;
119
128
  notify();
120
- _this.removeEventListener('loadend', _done);
121
- };
122
- this.addEventListener('loadend', _done);
123
- }
124
- for (var _len2 = arguments.length, args = new Array(_len2), _key2 = 0; _key2 < _len2; _key2++) {
125
- args[_key2] = arguments[_key2];
126
- }
127
- return originalSend.apply(this, args);
128
- };
129
- }
129
+ var _done = function done() {
130
+ g.inFlight -= 1;
131
+ if (g.inFlight < 0) g.inFlight = 0;
132
+ notify();
133
+ _this.removeEventListener('loadend', _done);
134
+ };
135
+ this.addEventListener('loadend', _done);
136
+ }
137
+ for (var _len2 = arguments.length, args = new Array(_len2), _key2 = 0; _key2 < _len2; _key2++) {
138
+ args[_key2] = arguments[_key2];
139
+ }
140
+ return g.originalSend.apply(this, args);
141
+ };
142
+ }
143
+
144
+ // ---- fetch hook ----
145
+ g.originalFetch = window.fetch;
146
+ if (typeof g.originalFetch === 'function') {
147
+ window.fetch = /*#__PURE__*/(0, _asyncToGenerator2["default"])(/*#__PURE__*/_regenerator["default"].mark(function _callee2() {
148
+ var _len3,
149
+ args,
150
+ _key3,
151
+ url,
152
+ track,
153
+ _args2 = arguments;
154
+ return _regenerator["default"].wrap(function (_context2) {
155
+ while (1) switch (_context2.prev = _context2.next) {
156
+ case 0:
157
+ for (_len3 = _args2.length, args = new Array(_len3), _key3 = 0; _key3 < _len3; _key3++) {
158
+ args[_key3] = _args2[_key3];
159
+ }
160
+ url = args === null || args === void 0 ? void 0 : args[0];
161
+ track = isGltfUrl(url);
162
+ if (track) {
163
+ _context2.next = 1;
164
+ break;
165
+ }
166
+ return _context2.abrupt("return", g.originalFetch.apply(this, args));
167
+ case 1:
168
+ g.inFlight += 1;
169
+ notify();
170
+ _context2.prev = 2;
171
+ _context2.next = 3;
172
+ return g.originalFetch.apply(this, args);
173
+ case 3:
174
+ return _context2.abrupt("return", _context2.sent);
175
+ case 4:
176
+ _context2.prev = 4;
177
+ g.inFlight -= 1;
178
+ if (g.inFlight < 0) g.inFlight = 0;
179
+ notify();
180
+ return _context2.finish(4);
181
+ case 5:
182
+ case "end":
183
+ return _context2.stop();
184
+ }
185
+ }, _callee2, this, [[2,, 4, 5]]);
186
+ }));
187
+ }
188
+ g.installed = true;
189
+ };
130
190
 
131
- // ---- fetch hook ----
132
- var originalFetch = window.fetch;
133
- if (typeof originalFetch === 'function') {
134
- window.fetch = /*#__PURE__*/(0, _asyncToGenerator2["default"])(/*#__PURE__*/_regenerator["default"].mark(function _callee2() {
135
- var _len3,
136
- args,
137
- _key3,
138
- url,
139
- track,
140
- _args2 = arguments;
141
- return _regenerator["default"].wrap(function (_context2) {
142
- while (1) switch (_context2.prev = _context2.next) {
191
+ // “No grace” but safe: require idle to remain idle across 2 RAF frames.
192
+ function waitStableIdle2Frames() {
193
+ return _waitStableIdle2Frames.apply(this, arguments);
194
+ }
195
+ function _waitStableIdle2Frames() {
196
+ _waitStableIdle2Frames = (0, _asyncToGenerator2["default"])(/*#__PURE__*/_regenerator["default"].mark(function _callee5() {
197
+ return _regenerator["default"].wrap(function (_context5) {
198
+ while (1) switch (_context5.prev = _context5.next) {
143
199
  case 0:
144
- for (_len3 = _args2.length, args = new Array(_len3), _key3 = 0; _key3 < _len3; _key3++) {
145
- args[_key3] = _args2[_key3];
146
- }
147
- url = args === null || args === void 0 ? void 0 : args[0];
148
- track = isGltfUrl(url);
149
- if (track) {
150
- _context2.next = 1;
200
+ _context5.next = 1;
201
+ return nextFrame();
202
+ case 1:
203
+ if (!(g.inFlight !== 0)) {
204
+ _context5.next = 2;
151
205
  break;
152
206
  }
153
- return _context2.abrupt("return", originalFetch.apply(this, args));
154
- case 1:
155
- inFlight += 1;
156
- notify();
157
- _context2.prev = 2;
158
- _context2.next = 3;
159
- return originalFetch.apply(this, args);
207
+ return _context5.abrupt("return", false);
208
+ case 2:
209
+ _context5.next = 3;
210
+ return nextFrame();
160
211
  case 3:
161
- return _context2.abrupt("return", _context2.sent);
212
+ return _context5.abrupt("return", g.inFlight === 0);
162
213
  case 4:
163
- _context2.prev = 4;
164
- inFlight -= 1;
165
- if (inFlight < 0) inFlight = 0;
166
- notify();
167
- return _context2.finish(4);
168
- case 5:
169
214
  case "end":
170
- return _context2.stop();
215
+ return _context5.stop();
171
216
  }
172
- }, _callee2, this, [[2,, 4, 5]]);
217
+ }, _callee5);
173
218
  }));
219
+ return _waitStableIdle2Frames.apply(this, arguments);
174
220
  }
175
- var subscribe = function subscribe(fn) {
176
- listeners.add(fn);
177
- // IMPORTANT: emits synchronously
178
- fn(inFlight);
179
- return function () {
180
- return listeners["delete"](fn);
181
- };
182
- };
183
-
184
- /**
185
- * Wait until inFlight becomes 0 (with grace window).
186
- * Safe even when already idle.
187
- */
188
221
  var waitForIdle = /*#__PURE__*/function () {
189
- var _ref2 = (0, _asyncToGenerator2["default"])(/*#__PURE__*/_regenerator["default"].mark(function _callee3() {
222
+ var _ref2 = (0, _asyncToGenerator2["default"])(/*#__PURE__*/_regenerator["default"].mark(function _callee4() {
190
223
  var _ref3,
191
224
  _ref3$timeoutMs,
192
225
  timeoutMs,
193
- _ref3$graceMs,
194
- graceMs,
195
226
  start,
196
- _args3 = arguments;
197
- return _regenerator["default"].wrap(function (_context3) {
198
- while (1) switch (_context3.prev = _context3.next) {
227
+ _args4 = arguments;
228
+ return _regenerator["default"].wrap(function (_context4) {
229
+ while (1) switch (_context4.prev = _context4.next) {
199
230
  case 0:
200
- _ref3 = _args3.length > 0 && _args3[0] !== undefined ? _args3[0] : {}, _ref3$timeoutMs = _ref3.timeoutMs, timeoutMs = _ref3$timeoutMs === void 0 ? 30000 : _ref3$timeoutMs, _ref3$graceMs = _ref3.graceMs, graceMs = _ref3$graceMs === void 0 ? 50 : _ref3$graceMs;
201
- start = Date.now();
202
- if (!(graceMs > 0)) {
203
- _context3.next = 1;
231
+ _ref3 = _args4.length > 0 && _args4[0] !== undefined ? _args4[0] : {}, _ref3$timeoutMs = _ref3.timeoutMs, timeoutMs = _ref3$timeoutMs === void 0 ? 30000 : _ref3$timeoutMs;
232
+ start = Date.now(); // fast-ish path: already stable idle
233
+ _context4.next = 1;
234
+ return waitStableIdle2Frames();
235
+ case 1:
236
+ if (!_context4.sent) {
237
+ _context4.next = 2;
204
238
  break;
205
239
  }
206
- _context3.next = 1;
207
- return sleep(graceMs);
208
- case 1:
209
- return _context3.abrupt("return", new Promise(function (resolve, reject) {
240
+ return _context4.abrupt("return", true);
241
+ case 2:
242
+ return _context4.abrupt("return", new Promise(function (resolve, reject) {
210
243
  var unsub = null;
211
- var onChange = function onChange(count) {
212
- if (count === 0) {
213
- if (unsub) unsub();
214
- resolve(true);
215
- return;
216
- }
217
- if (Date.now() - start > timeoutMs) {
218
- if (unsub) unsub();
219
- reject(new Error('GLTF did not become idle within timeout'));
220
- }
221
- };
244
+ var onChange = /*#__PURE__*/function () {
245
+ var _ref4 = (0, _asyncToGenerator2["default"])(/*#__PURE__*/_regenerator["default"].mark(function _callee3(count) {
246
+ var stable;
247
+ return _regenerator["default"].wrap(function (_context3) {
248
+ while (1) switch (_context3.prev = _context3.next) {
249
+ case 0:
250
+ if (!(count !== 0)) {
251
+ _context3.next = 1;
252
+ break;
253
+ }
254
+ if (Date.now() - start > timeoutMs) {
255
+ if (unsub) unsub();
256
+ reject(new Error('GLTF did not become idle within timeout'));
257
+ }
258
+ return _context3.abrupt("return");
259
+ case 1:
260
+ _context3.next = 2;
261
+ return waitStableIdle2Frames();
262
+ case 2:
263
+ stable = _context3.sent;
264
+ if (!stable) {
265
+ _context3.next = 3;
266
+ break;
267
+ }
268
+ if (unsub) unsub();
269
+ resolve(true);
270
+ return _context3.abrupt("return");
271
+ case 3:
272
+ if (Date.now() - start > timeoutMs) {
273
+ if (unsub) unsub();
274
+ reject(new Error('GLTF did not become idle within timeout'));
275
+ }
276
+ case 4:
277
+ case "end":
278
+ return _context3.stop();
279
+ }
280
+ }, _callee3);
281
+ }));
282
+ return function onChange(_x) {
283
+ return _ref4.apply(this, arguments);
284
+ };
285
+ }();
222
286
  unsub = subscribe(onChange);
223
287
  }));
224
- case 2:
288
+ case 3:
225
289
  case "end":
226
- return _context3.stop();
290
+ return _context4.stop();
227
291
  }
228
- }, _callee3);
292
+ }, _callee4);
229
293
  }));
230
294
  return function waitForIdle() {
231
295
  return _ref2.apply(this, arguments);
@@ -233,34 +297,42 @@ function installGltfTracker() {
233
297
  }();
234
298
  var uninstall = function uninstall() {
235
299
  var _XHR$prototype3, _XHR$prototype4;
236
- if (XHR !== null && XHR !== void 0 && (_XHR$prototype3 = XHR.prototype) !== null && _XHR$prototype3 !== void 0 && _XHR$prototype3.open && originalOpen) XHR.prototype.open = originalOpen;
237
- if (XHR !== null && XHR !== void 0 && (_XHR$prototype4 = XHR.prototype) !== null && _XHR$prototype4 !== void 0 && _XHR$prototype4.send && originalSend) XHR.prototype.send = originalSend;
238
- if (typeof originalFetch === 'function') window.fetch = originalFetch;
239
- listeners.clear();
240
- inFlight = 0;
300
+ g.refCount -= 1;
301
+ if (g.refCount > 0) return;
302
+ var XHR = window.XMLHttpRequest;
303
+ if (XHR !== null && XHR !== void 0 && (_XHR$prototype3 = XHR.prototype) !== null && _XHR$prototype3 !== void 0 && _XHR$prototype3.open && g.originalOpen) XHR.prototype.open = g.originalOpen;
304
+ if (XHR !== null && XHR !== void 0 && (_XHR$prototype4 = XHR.prototype) !== null && _XHR$prototype4 !== void 0 && _XHR$prototype4.send && g.originalSend) XHR.prototype.send = g.originalSend;
305
+ if (typeof g.originalFetch === 'function') window.fetch = g.originalFetch;
306
+ g.listeners.clear();
307
+ g.inFlight = 0;
308
+ g.installed = false;
309
+ g.originalFetch = null;
310
+ g.originalOpen = null;
311
+ g.originalSend = null;
241
312
  };
313
+ g.refCount += 1;
314
+ installIfNeeded();
242
315
  return {
243
316
  getInFlight: function getInFlight() {
244
- return inFlight;
317
+ return g.inFlight;
245
318
  },
246
319
  waitForIdle: waitForIdle,
247
320
  uninstall: uninstall
248
321
  };
249
322
  }
250
323
  function renderKitchenSimulator(container) {
251
- var _props$framesPerEvent, _props$waitForGltfIdl, _props$gltfTimeoutMs, _props$gltfGraceMs, _props$syncGltfGraceM, _props$syncExtraFrame;
324
+ var _props$framesPerEvent, _props$waitForGltfIdl, _props$gltfTimeoutMs, _props$syncExtraFrame;
252
325
  var props = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
253
326
  if (!container) throw new Error('renderKitchenSimulator: container is required');
254
327
 
255
- // ✅ Reuse existing API for same container
328
+ // ✅ Reuse existing API
256
329
  if (container[API_KEY]) {
257
330
  var _container$API_KEY$__, _container$API_KEY;
258
- // update render with latest props (safe)
259
331
  (_container$API_KEY$__ = (_container$API_KEY = container[API_KEY]).__render) === null || _container$API_KEY$__ === void 0 || _container$API_KEY$__.call(_container$API_KEY, props);
260
332
  return container[API_KEY];
261
333
  }
262
334
 
263
- // ✅ Reuse root for same container
335
+ // ✅ Reuse root
264
336
  var root = container[ROOT_KEY];
265
337
  if (!root) {
266
338
  root = (0, _client.createRoot)(container);
@@ -268,90 +340,83 @@ function renderKitchenSimulator(container) {
268
340
  }
269
341
  var setExternalEventFn = null;
270
342
  var destroyed = false;
271
-
272
- // queue + marker handling
273
343
  var queue = [];
274
344
  var pendingMarkers = new Set();
275
345
  var MARKER = Symbol('marker');
276
346
  var gltfTracker = installGltfTracker();
277
347
 
278
- // defaults
279
- var defaultFramesPerEvent = (_props$framesPerEvent = props.framesPerEvent) !== null && _props$framesPerEvent !== void 0 ? _props$framesPerEvent : 2;
348
+ // ---- FAST defaults (still safe) ----
349
+ var defaultFramesPerEvent = (_props$framesPerEvent = props.framesPerEvent) !== null && _props$framesPerEvent !== void 0 ? _props$framesPerEvent : 1; // was 2
280
350
  var waitForGltf = (_props$waitForGltfIdl = props.waitForGltfIdleAfterEachEvent) !== null && _props$waitForGltfIdl !== void 0 ? _props$waitForGltfIdl : true;
281
351
  var defaultTimeout = (_props$gltfTimeoutMs = props.gltfTimeoutMs) !== null && _props$gltfTimeoutMs !== void 0 ? _props$gltfTimeoutMs : 30000;
282
- var defaultGrace = (_props$gltfGraceMs = props.gltfGraceMs) !== null && _props$gltfGraceMs !== void 0 ? _props$gltfGraceMs : 50;
283
- var syncGrace = (_props$syncGltfGraceM = props.syncGltfGraceMs) !== null && _props$syncGltfGraceM !== void 0 ? _props$syncGltfGraceM : 350; // SyncScene uses larger grace
284
- var syncExtraFrames = (_props$syncExtraFrame = props.syncExtraFrames) !== null && _props$syncExtraFrame !== void 0 ? _props$syncExtraFrame : 2;
352
+ var syncExtraFrames = (_props$syncExtraFrame = props.syncExtraFrames) !== null && _props$syncExtraFrame !== void 0 ? _props$syncExtraFrame : 1; // was 2
353
+
285
354
  var draining = false;
286
355
  function isSyncScene(ev) {
287
356
  var _ev$payload;
288
- return (ev === null || ev === void 0 ? void 0 : ev.type) === 'EXTERNAL_EVENT_SYNC_SCENE' || (ev === null || ev === void 0 || (_ev$payload = ev.payload) === null || _ev$payload === void 0 ? void 0 : _ev$payload.mode) === 'sync-scene' ||
289
- // if you pass mode sometimes
290
- (ev === null || ev === void 0 ? void 0 : ev.__sync) === true;
357
+ return (ev === null || ev === void 0 ? void 0 : ev.type) === 'EXTERNAL_EVENT_SYNC_SCENE' || (ev === null || ev === void 0 || (_ev$payload = ev.payload) === null || _ev$payload === void 0 ? void 0 : _ev$payload.mode) === 'sync-scene' || (ev === null || ev === void 0 ? void 0 : ev.__sync) === true;
291
358
  }
292
- function settle(_x) {
359
+ function settle(_x2) {
293
360
  return _settle.apply(this, arguments);
294
361
  }
295
362
  function _settle() {
296
- _settle = (0, _asyncToGenerator2["default"])(/*#__PURE__*/_regenerator["default"].mark(function _callee5(ev) {
297
- var _ev$framesPerEvent, _ev$gltfGraceMs, _ev$gltfTimeoutMs;
298
- var frames, i, graceMs, timeoutMs, _i;
299
- return _regenerator["default"].wrap(function (_context5) {
300
- while (1) switch (_context5.prev = _context5.next) {
363
+ _settle = (0, _asyncToGenerator2["default"])(/*#__PURE__*/_regenerator["default"].mark(function _callee7(ev) {
364
+ var _ev$framesPerEvent, _ev$gltfTimeoutMs;
365
+ var frames, i, timeoutMs, _i;
366
+ return _regenerator["default"].wrap(function (_context7) {
367
+ while (1) switch (_context7.prev = _context7.next) {
301
368
  case 0:
302
- frames = (_ev$framesPerEvent = ev === null || ev === void 0 ? void 0 : ev.framesPerEvent) !== null && _ev$framesPerEvent !== void 0 ? _ev$framesPerEvent : defaultFramesPerEvent; // 1) allow React + reducers to run
369
+ frames = (_ev$framesPerEvent = ev === null || ev === void 0 ? void 0 : ev.framesPerEvent) !== null && _ev$framesPerEvent !== void 0 ? _ev$framesPerEvent : defaultFramesPerEvent; // 1) allow reducers/react to run
303
370
  i = 0;
304
371
  case 1:
305
372
  if (!(i < frames)) {
306
- _context5.next = 3;
373
+ _context7.next = 3;
307
374
  break;
308
375
  }
309
- _context5.next = 2;
376
+ _context7.next = 2;
310
377
  return nextFrame();
311
378
  case 2:
312
379
  i += 1;
313
- _context5.next = 1;
380
+ _context7.next = 1;
314
381
  break;
315
382
  case 3:
316
383
  if (waitForGltf) {
317
- _context5.next = 4;
384
+ _context7.next = 4;
318
385
  break;
319
386
  }
320
- return _context5.abrupt("return");
387
+ return _context7.abrupt("return");
321
388
  case 4:
322
- // 2) wait for gltf idle
323
- graceMs = isSyncScene(ev) ? syncGrace : (_ev$gltfGraceMs = ev === null || ev === void 0 ? void 0 : ev.gltfGraceMs) !== null && _ev$gltfGraceMs !== void 0 ? _ev$gltfGraceMs : defaultGrace;
389
+ // 2) wait for gltf idle (stable-idle 2 frames, no time grace)
324
390
  timeoutMs = (_ev$gltfTimeoutMs = ev === null || ev === void 0 ? void 0 : ev.gltfTimeoutMs) !== null && _ev$gltfTimeoutMs !== void 0 ? _ev$gltfTimeoutMs : defaultTimeout;
325
- _context5.next = 5;
391
+ _context7.next = 5;
326
392
  return gltfTracker.waitForIdle({
327
- graceMs: graceMs,
328
393
  timeoutMs: timeoutMs
329
394
  });
330
395
  case 5:
331
- _context5.next = 6;
396
+ _context7.next = 6;
332
397
  return nextFrame();
333
398
  case 6:
334
399
  if (!isSyncScene(ev)) {
335
- _context5.next = 9;
400
+ _context7.next = 9;
336
401
  break;
337
402
  }
338
403
  _i = 0;
339
404
  case 7:
340
405
  if (!(_i < syncExtraFrames)) {
341
- _context5.next = 9;
406
+ _context7.next = 9;
342
407
  break;
343
408
  }
344
- _context5.next = 8;
409
+ _context7.next = 8;
345
410
  return nextFrame();
346
411
  case 8:
347
412
  _i += 1;
348
- _context5.next = 7;
413
+ _context7.next = 7;
349
414
  break;
350
415
  case 9:
351
416
  case "end":
352
- return _context5.stop();
417
+ return _context7.stop();
353
418
  }
354
- }, _callee5);
419
+ }, _callee7);
355
420
  }));
356
421
  return _settle.apply(this, arguments);
357
422
  }
@@ -359,57 +424,60 @@ function renderKitchenSimulator(container) {
359
424
  return _drain.apply(this, arguments);
360
425
  }
361
426
  function _drain() {
362
- _drain = (0, _asyncToGenerator2["default"])(/*#__PURE__*/_regenerator["default"].mark(function _callee6() {
427
+ _drain = (0, _asyncToGenerator2["default"])(/*#__PURE__*/_regenerator["default"].mark(function _callee8() {
363
428
  var item;
364
- return _regenerator["default"].wrap(function (_context6) {
365
- while (1) switch (_context6.prev = _context6.next) {
429
+ return _regenerator["default"].wrap(function (_context8) {
430
+ while (1) switch (_context8.prev = _context8.next) {
366
431
  case 0:
367
432
  if (!(draining || destroyed)) {
368
- _context6.next = 1;
433
+ _context8.next = 1;
369
434
  break;
370
435
  }
371
- return _context6.abrupt("return");
436
+ return _context8.abrupt("return");
372
437
  case 1:
373
438
  draining = true;
374
- _context6.prev = 2;
439
+ _context8.prev = 2;
375
440
  case 3:
376
- if (!(queue.length && !destroyed)) {
377
- _context6.next = 8;
441
+ if (!(!destroyed && queue.length)) {
442
+ _context8.next = 8;
378
443
  break;
379
444
  }
380
- item = queue.shift(); // marker?
381
- if (!(item && item.__marker === MARKER)) {
382
- _context6.next = 4;
445
+ if (setExternalEventFn) {
446
+ _context8.next = 5;
383
447
  break;
384
448
  }
385
- pendingMarkers["delete"](item.token);
386
- return _context6.abrupt("continue", 3);
449
+ _context8.next = 4;
450
+ return nextFrame();
387
451
  case 4:
388
452
  if (setExternalEventFn) {
389
- _context6.next = 6;
453
+ _context8.next = 5;
390
454
  break;
391
455
  }
392
- _context6.next = 5;
393
- return nextFrame();
456
+ return _context8.abrupt("continue", 3);
394
457
  case 5:
395
- queue.unshift(item); // put back and retry
396
- return _context6.abrupt("continue", 3);
458
+ item = queue.shift();
459
+ if (!(item && item.__marker === MARKER)) {
460
+ _context8.next = 6;
461
+ break;
462
+ }
463
+ pendingMarkers["delete"](item.token);
464
+ return _context8.abrupt("continue", 3);
397
465
  case 6:
398
466
  setExternalEventFn(item);
399
- _context6.next = 7;
467
+ _context8.next = 7;
400
468
  return settle(item);
401
469
  case 7:
402
- _context6.next = 3;
470
+ _context8.next = 3;
403
471
  break;
404
472
  case 8:
405
- _context6.prev = 8;
473
+ _context8.prev = 8;
406
474
  draining = false;
407
- return _context6.finish(8);
475
+ return _context8.finish(8);
408
476
  case 9:
409
477
  case "end":
410
- return _context6.stop();
478
+ return _context8.stop();
411
479
  }
412
- }, _callee6, null, [[2,, 8, 9]]);
480
+ }, _callee8, null, [[2,, 8, 9]]);
413
481
  }));
414
482
  return _drain.apply(this, arguments);
415
483
  }
@@ -453,14 +521,9 @@ function renderKitchenSimulator(container) {
453
521
  }]);
454
522
  }(_react["default"].Component);
455
523
  var api = {
456
- // internal: rerender wrapper with latest props if host calls renderKitchenSimulator again
457
524
  __render: function __render(nextProps) {
458
525
  root.render(/*#__PURE__*/_react["default"].createElement(Wrapper, nextProps));
459
526
  },
460
- /**
461
- * Send one or many events (in order).
462
- * Resolves when this batch has been delivered + settled.
463
- */
464
527
  sendExternalEvents: function sendExternalEvents(eventOrEvents) {
465
528
  var events = Array.isArray(eventOrEvents) ? eventOrEvents : [eventOrEvents];
466
529
  var _iterator2 = _createForOfIteratorHelper(events),
@@ -482,37 +545,39 @@ function renderKitchenSimulator(container) {
482
545
  token: token
483
546
  });
484
547
  drain();
548
+
549
+ // keep same semantics (resolve when marker cleared)
485
550
  return new Promise(function (resolve) {
486
551
  var check = /*#__PURE__*/function () {
487
- var _ref4 = (0, _asyncToGenerator2["default"])(/*#__PURE__*/_regenerator["default"].mark(function _callee4() {
488
- return _regenerator["default"].wrap(function (_context4) {
489
- while (1) switch (_context4.prev = _context4.next) {
552
+ var _ref5 = (0, _asyncToGenerator2["default"])(/*#__PURE__*/_regenerator["default"].mark(function _callee6() {
553
+ return _regenerator["default"].wrap(function (_context6) {
554
+ while (1) switch (_context6.prev = _context6.next) {
490
555
  case 0:
491
556
  if (destroyed) {
492
- _context4.next = 3;
557
+ _context6.next = 3;
493
558
  break;
494
559
  }
495
560
  if (!pendingMarkers.has(token)) {
496
- _context4.next = 2;
561
+ _context6.next = 2;
497
562
  break;
498
563
  }
499
- _context4.next = 1;
564
+ _context6.next = 1;
500
565
  return nextFrame();
501
566
  case 1:
502
- return _context4.abrupt("continue", 0);
567
+ return _context6.abrupt("continue", 0);
503
568
  case 2:
504
569
  resolve(true);
505
- return _context4.abrupt("return");
570
+ return _context6.abrupt("return");
506
571
  case 3:
507
572
  resolve(false);
508
573
  case 4:
509
574
  case "end":
510
- return _context4.stop();
575
+ return _context6.stop();
511
576
  }
512
- }, _callee4);
577
+ }, _callee6);
513
578
  }));
514
579
  return function check() {
515
- return _ref4.apply(this, arguments);
580
+ return _ref5.apply(this, arguments);
516
581
  };
517
582
  }();
518
583
  check();
@@ -529,8 +594,6 @@ function renderKitchenSimulator(container) {
529
594
  destroyed = true;
530
595
  api.clearQueue();
531
596
  gltfTracker.uninstall();
532
-
533
- // ✅ defer unmount to avoid "unmount while React is rendering"
534
597
  var doUnmount = function doUnmount() {
535
598
  try {
536
599
  root.unmount();
@@ -539,16 +602,10 @@ function renderKitchenSimulator(container) {
539
602
  container[API_KEY] = null;
540
603
  }
541
604
  };
542
-
543
- // Prefer microtask when available, otherwise macrotask
544
605
  if (typeof queueMicrotask === 'function') queueMicrotask(doUnmount);else setTimeout(doUnmount, 0);
545
606
  }
546
607
  };
547
-
548
- // first render
549
608
  api.__render(props);
550
-
551
- // store api on container so repeated calls reuse it
552
609
  container[API_KEY] = api;
553
610
  return api;
554
611
  }