()
| 10541 | hidden tab pauses rAF, and the only way to step the world in that state is to |
| 10542 | have a tick that does not re-queue itself. */ |
| 10543 | function tick(){ |
| 10544 | if(disposed)return; |
| 10545 | const t=clock.getElapsedTime(), dt=Math.min(0.05,t-last); last=t; |
| 10546 | /* The overlay covers the whole canvas with an opaque surface for as long as |
| 10547 | this is loading, and a frame costs three passes over the scene plus a label |
| 10548 | solve. Painting them under it is what was stealing time from the chunked |
| 10549 | build the progress bar is reporting on. boot() draws one real frame the |
| 10550 | moment it flips to ready, so nothing is ever revealed unpainted. */ |
| 10551 | const curtained=STATE.status==='loading'; |
| 10552 | if(resizeDirty){ resizeDirty=false; reflow(); } |
| 10553 | |
| 10554 | if(W){ |
| 10555 | /* Before anything reads DAY this frame, and before the land rebuild below, |
| 10556 | so a scrubbed day is fully standing by the time this frame draws. */ |
| 10557 | flushSeek(); |
| 10558 | if(playing){ |
| 10559 | acc+=dt*DPS*speed; |
| 10560 | let stepped=false; |
| 10561 | while(acc>=1&&DAY<W.nT-1){ acc-=1; step(DAY+1); stepped=true; } |
| 10562 | /* Once for the frame, not once per day crossed. At 16x a frame can cross |
| 10563 | two dozen days, and only the last one is ever drawn or emitted — the |
| 10564 | per-day work inside step (toasts, pulses, level-up queueing) stays |
| 10565 | where it is, because those are events rather than a state to paint. */ |
| 10566 | if(stepped) updateHud(); |
| 10567 | if(DAY>=W.nT-1) stop(); |
| 10568 | } |
| 10569 | /* A realm's LAND only changes ten times over a whole history, but the |
| 10570 | monuments standing on it change constantly — and refreshing a realm costs |
| 10571 | ~100ms, so doing it per level-up stutters and doing it only on pause left |
| 10572 | the world visibly frozen while the numbers climbed. So: at most one realm |
| 10573 | refresh every 0.4s, oldest first, playing or not. */ |
| 10574 | if(!OPEN&&!queue.length&&!active.length&&t-lastSky>0.4){ |
| 10575 | const q=W.quarters.find(x=>x.skyStale&&x.island&&HAND.x!==x); |
| 10576 | if(q){ q.skyStale=false; lastSky=t; raiseRealm(q,realmLevelOf(q.shown),playing); } |
| 10577 | } |
| 10578 | /* Queued rebuilds, two a frame — one level-up is ~40 ms of work and a burst |
| 10579 | of them at 16× would otherwise land in a single frame. */ |
| 10580 | for(let n=0;n<2&&queue.length;n++){ |
| 10581 | const it=queue.shift(); const L=it.queued; it.queued=0; |
| 10582 | if(!L)continue; |
| 10583 | /* Rebuilding what the hand is holding would dispose the group mid-swing. |
| 10584 | It waits its turn; you cannot hold a town for long enough to matter. */ |
| 10585 | if(HAND.x===it){ it.queued=L; queue.push(it); continue; } |
| 10586 | if(it.list) raiseRealm(it,L,true); |
| 10587 | else if(L!==it.level) raise(it,L,true); |
| 10588 | } |
| 10589 | /* The transition: everything already standing keeps its exact transform, |
| 10590 | and only the delta animates — new land RISES, new structure BUILDS. */ |
| 10591 | for(let i=active.length-1;i>=0;i--){ |
| 10592 | const d=active[i], age=t-d.t0; let live=false; |
| 10593 | for(const nd of d.nodes||[]){ |
| 10594 | if(nd.done)continue; |
| 10595 | live=true; |
| 10596 | if(nd.mode==='rise'){ |
| 10597 | const u=clamp(age/RISE,0,1); |
| 10598 | nd.obj.position.y=lerp(-1.8,0,smooth(u)); |
| 10599 | if(u>=1){ nd.obj.position.y=0; nd.done=true; } |
| 10600 | }else if(nd.mode==='build'){ |
no test coverage detected