({ cap, until }: { cap: number; until: () => boolean })
| 45 | } |
| 46 | |
| 47 | async drive({ cap, until }: { cap: number; until: () => boolean }) { |
| 48 | let ticks = 0 |
| 49 | while (this.running && ticks < cap) { |
| 50 | globalThis.mockRaf.step() // advance the clock so each frame has dt > 0 |
| 51 | let repeat = 0 |
| 52 | |
| 53 | // flushGlobalEffects('before') === the three target's addEffect; rafz |
| 54 | // update() runs here and fires onDemand while it has a queue. |
| 55 | raf.advance() |
| 56 | |
| 57 | if (this.frames > 0) { |
| 58 | // update(): no useFrame subscribers; render, then decrement. |
| 59 | this.frames = Math.max(0, this.frames - 1) |
| 60 | repeat += this.frames |
| 61 | } |
| 62 | |
| 63 | // Nothing kept the loop alive this frame → r3f stops it... |
| 64 | if (repeat === 0) this.running = false |
| 65 | |
| 66 | await flushMicroTasks() // ...the deferred invalidate (and loop restarts) land here |
| 67 | ticks++ |
| 68 | if (until()) break |
| 69 | } |
| 70 | return ticks |
| 71 | } |
| 72 | } |
| 73 | |
| 74 | describe('frameLoop "demand"', () => { |
no test coverage detected