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

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