---
title: "Snel op een goedkope tablet"
description: "Hoe Professor Oops een pagina vol verf in beweging houdt op een goedkope tablet: een Web Worker, zeven WebAssembly-kernels getest tegen hun tweelingen, en de hand die als eerste aan de beurt is."
source_name: "Game Tailors"
source_url: "https://professoroops.com/binnenin/snelheid/"
site_home: "https://professoroops.com/"
source_description: "De teken-app waarin het papier echt is. Geen reclame. Geen accounts. Geen persoonsgegevens: alleen anonieme tellingen, en die kun je uitzetten."
locale: "nl"
legal:
  - "Game Tailors · Schieweg 15Y-40, 2627 AN Delft (NL)"
  - "KvK 92437702 · VAT NL866044474B01"
  - "info@gametailors.com · +31 6 4227 5919"
copyright: "© 2026 Game Tailors"
published_at: "2026-11-11T11:19:31.870Z"
modified_at: "2026-11-11T11:19:31.870Z"
---

# Snel op een goedkope tablet

## De verf onder de vinger van je kind blijft bewegen, zelfs op een goedkope tablet

Elk plekje van de pagina heeft zijn eigen water, kleur, smurrie en warmte, en een grote pagina heeft bijna tweehonderdduizend plekjes. Een budgettablet kan ze niet allemaal zestig keer per seconde bijwerken. Dus het spel laat de rustige delen van de pagina rusten, doet zijn zwaarste sommen in een snellere taal en helpt de plek onder de vinger als eerste. De rest haalt het een moment later in.

[Voor technici](<#hood-engineers>)

![Geschilderde illustratie van een tablet en een telefoon op een geel vel met een ketchupzigzag, op beide schermen verfspetters, melkwervelingen en een waskrijthuisje, en de schilder die er glimlachend naar kijkt.](<https://professoroops.com/_assets/entity_behXKeDXPUwYbHHJZMv7.webp>)

## Tekenen en simuleren lopen naast elkaar, zodat de vinger nooit op de verf hoeft te wachten

Professor Oops draait als twee helften die niet op elkaar wachten. De ene helft luistert naar de vinger van je kind en tekent het scherm. De andere rekent uit wat de ketchup, het water en het vuur hierna doen. Die tweede helft draait in een Web Worker, een aparte werklijn die de browser aan een webpagina geeft. De twee geven elkaar vele keren per seconde briefjes door.

Dus een pagina die zwemt in de verf, kan de hand niet laten bevriezen. Terwijl de simulatie bezig is, tekent het scherm nog steeds de kwast of de lepel in de hand van je kind uit het nieuwste nieuws dat het heeft, elke keer dat het scherm ververst.

De tekenhelft heeft geen kopie van de wereld. Ze krijgt een replica: de dingen op de pagina \(een bal, een kaars, een strooisel glitter\), verstuurd als alleen wat er sinds het vorige briefje veranderde, en plaatjes van de vierkantjes papier die veranderden. Een test mislukt als tekencode rechtstreeks naar de simulatie grijpt, want dat soort fout werkt als alles samen draait en doet stilletjes niets in de worker. De kop van de test zelf zegt dat het vier keer is gebeurd.

Als de worker niet kan starten, schakelt het spel vanzelf over en draait het de simulatie in plaats daarvan naast het tekenen. Wat je kind al had gedaan, gaat mee.

De verf onder de vinger van je kind blijft bewegen, zelfs op een goedkope tablet

Voor technici

### De verf onder de vinger van je kind blijft bewegen, zelfs op een goedkope tablet

De hele engine draait in een Web Worker; de hoofdthread tekent uit een compacte replica en uploadt alleen de vierkantjes papier die veranderden. Zeven WebAssembly-kernels \(vier gebruiken SIMD in het uitgebrachte spel\) houden hun JavaScript-tweelingen: vijf zijn getest als gelijk tot op de bit, twee binnen de afronding van 32-bits floats. Elke simulatie in tegels heeft een eigen klok: de vierkantjes van de hand gaan eerst, elk vierkantje krijgt gegarandeerd een beurt binnen een begrensde wachttijd, en een vierkantje dat te laat is, haalt in met één langere stap, onder een stabiliteitsgrens gehouden.

[Onder de motorkap](<#hood-worker>)

Tekenen en simuleren lopen naast elkaar, zodat de vinger nooit op de verf hoeft te wachten

Onder de motorkap

### Tekenen en simuleren lopen naast elkaar, zodat de vinger nooit op de verf hoeft te wachten

De worker bevat de hele engine. De hoofdthread stuurt invoer op het moment dat die gebeurt, en een vaste tik met de tijd die is verstreken. De worker laat de simulatie stappen zetten van vast 1/60 s en antwoordt met een beeld: de veranderde stukken van de plaatjes van de pagina, de replica, de geluiden die de stap maakte en zijn eigen tijden. Er is maar één tik tegelijk onderweg en tijd die nog tegoed staat, telt op aan de kant van de hoofdthread, dus de simulatie schiet niet door en zit ook niet stil. De buffers van een beeld worden overgedragen, nooit gekopieerd, en voor hergebruik teruggegeven.

De replica stuurt alleen wat er veranderde. Een onveranderd voorwerp kost een paar bytes; een veranderd voorwerp stuurt alleen zijn veranderde waarden, ingepakt in platte getypeerde stromen. De drukste lijsten, zoals confetti en glitter, reizen als compacte rijen: het coderen op die pagina’s zakte naar 0,4× van de oude tijd, van 7,9 naar 3,1 ms op de drukste scène. Tekencode roept aan de kant van de hoofdthread nog steeds de eigen methoden van de voorwerpen aan, dus voor de code die tekent, voelt de replica als het echte werk.

Een WebAssembly-geheugen kan niet tussen threads worden doorgegeven, dus de worker kopieert alleen de veranderde vierkantjes eruit, die rond de hand eerst. Zonder uploadgrens houdt een automatische test vast dat wat er werd verstuurd, precies is wat een verse kopie van de hele pagina zou geven, tot op de bit, na elk beeld van 24 drukke scènes.

Als de worker na het starten te lang stil blijft, wordt elk bericht dat tot dan toe is verstuurd en als kopie bewaard, opnieuw afgespeeld in een simulatie op de hoofdthread, en een worker die te laat is, wordt gestopt, zodat er nooit twee simulaties draaien. Een test speelt een streek en 60 tikken op beide manieren af, en elk bewaard veld komt overeen.

### De rondgang van één beeld

Hoofdthread → Web Worker

#### Invoer

Meteen: je vinger, op het moment dat hij beweegt.

Hoofdthread → Web Worker

#### Tik

De tijd die is verstreken.

Web Worker → hoofdthread

#### Beeld

De veranderde tegels, de replica, de geluiden en de milliseconden die het kostte.

Hoofdthread → Web Worker

#### Buffers terug

Teruggegeven voor het volgende beeld, nooit gekopieerd.

Uit het ontwerp van de worker van het spel. Een streek verschijnt één beeld later dan wanneer alles op één thread zou draaien; in ruil daarvoor wordt de vinger nooit geblokkeerd.

## De zwaarste berekeningen draaien in een snellere vorm van code, en tests controleren dat ze dezelfde antwoorden geven

Zeven van de drukste lussen van het spel hebben een tweede, snellere versie in WebAssembly, een compacte vorm van code op laag niveau die browsers snel kunnen draaien. Ze dekken de druk van de wind, stromende smurrie, water en kleurstof die door papier kruipen, olie die op water drijft, vuur, zeep die over melk schiet en vingers die verf rondduwen. Vier ervan werken ook op meerdere getallen tegelijk \(SIMD, “single instruction, multiple data”\).

De leesbare JavaScript-versies blijven als referentie in het spel. De tests draaien beide op dezelfde rommelige pagina en vergelijken ze. Bij vijf van de zeven moet elk getal op de pagina tot op het laatste binaire cijfer overeenkomen. De andere twee, papier en de drijvende laag, ruilen een beetje afronding in voor snelheid en moeten binnen een honderdduizendste en een tienduizendste overeenkomen.

Als iemand de trage versie verandert en de snelle vergeet, houden de tests hem tegen. Als een telefoon de snelle versies helemaal niet kan draaien, gebruikt het spel de trage en speelt het bijna hetzelfde spel, met minder speling. Het ene bekende verschil: op het trage pad bij de twee laagste detailniveaus waait de wind iets zwakker.

[Onder de motorkap](<#hood-kernels>)

De zwaarste berekeningen draaien in een snellere vorm van code, en tests controleren dat ze dezelfde antwoorden geven

Onder de motorkap

### De zwaarste berekeningen draaien in een snellere vorm van code, en tests controleren dat ze dezelfde antwoorden geven

De kernels zijn geschreven in AssemblyScript, gecompileerd met SIMD aan, en meegeleverd in het eigen script van het spel, dus de apps halen niets extra op.

**Waarom de meeste exacte kernels doubles gebruiken.** JavaScript maakt zijn sommen in 64-bits floats, en opslaan in een 32-bits array rondt af. Een kernel die dezelfde bewerkingen in 64 bits doet, in dezelfde volgorde, afrondend op dezelfde momenten, komt er identiek uit. Smurrie, vuur, zeep en duwen doen dat, en betalen ervoor in vectorbreedte: vuur krijgt twee banen in plaats van vier, en de andere drie gebruiken er in het uitgebrachte spel geen. De duwkernel doet zelfs de eigen manier van de browser na om een afstand uit te rekenen, omdat de bibliotheek van de compiler af en toe anders afrondt. De vuurkernel haalt zijn willekeurige getallen uit dezelfde stroom als de JavaScript, bewaard in het gedeelde geheugen.

**De lucht doet het andersom.** Zijn JavaScript-tweeling rondt elke bewerking af op 32 bits, in een vaste volgorde, zodat de JavaScript overeenkomt met vier 32-bitsbanen. De oplosser is gedempte Jacobi-multigrid, gekozen omdat de Gauss-Seidel die hij verving scheef trok: tocht blies een vijfde harder de ene kant op dan de andere. Zie voor multigrid zelf <sup>[Brandt 1977](<https://professoroops.com/binnenin/onderzoek-simulatie/#brandt-1977>)</sup> en <sup>[Briggs 2000](<https://professoroops.com/binnenin/onderzoek-simulatie/#briggs-2000>)</sup>, later gevonden en in overeenstemming met de code.

**Drie lagen controle.**

- **Tweelinghashes.** Elke kernel noemt de JavaScript die hij kopieert, 141 functies en constanten in het uitgebrachte spel. Een buildstap hasht ze zonder commentaar en opmaak, en een test mislukt tot de kernel opnieuw is overgezet, of nagekeken met de nieuwe hash vastgelegd. Het bewijst “opnieuw bekeken”, niet “juist”.
- **Tweelingengines.** Hetzelfde startgetal, dezelfde pagina, één engine met één kernel en één zonder, met de andere kernels uit zodat hun afronding het niet kan vertroebelen. Smurrie, zeep en duwen vergelijken elke array van de wereld; vuur elk bewaard veld; lucht de wind op 12 roostergroottes, en dan elke array na 150 tikken. Elke test controleert ook dat de kernel echt heeft gedraaid.
- **Het hek.** Elk materiaal, droog en nat papier, een vuur, zes indelingen, alle kernels aan: hooguit 0,2% van de cellen mag meer dan 2 × 10<sup>−3</sup> verschillen. De gedragstests draaien de JavaScript-lussen en de apps draaien de kernels; dit hek verbindt de twee.

In de code voor de volgende update volgende update is één bekend verschil vastgelegd in plaats van verborgen: zes cellen langs de onderrand van een scheef vel, een paar tienduizendsten uit elkaar in één kleurstof. De test is gemarkeerd als mislukkend, dus hij meldt het op de dag dat het is opgelost.

### Probeer het: de eigen luchtkernel van het spel tegen zijn tweeling

De eigen regel van het spel Dit draait het echte werk: de WebAssembly-module van 4.199 bytes die het spel meelevert voor de drukoplossing van de wind, en een kopie van zijn JavaScript-tweeling. Een werveling roert aan beide kanten dezelfde wind, en na elke oplossing wordt elk van de getallen vergeleken. **Waar je op let:** nul getallen verschillen, oplossing na oplossing. Druk dan op **Nudge the twin by one bit**: dat verandert één gewicht in de JavaScript met de kleinste stap die een 32-bits float kan zetten, en de twee lopen binnen één oplossing uit elkaar. De tijden worden op jouw apparaat gemeten, nu.

![De eigen luchtkernel van het spel tegen zijn tweeling](<https://professoroops.com/_assets/entity_GAbLsTF282lGAmdCTvMl.png>)

Oplossingen vergeleken

Getallen die verschillen, laatste oplossing

JavaScript-tweeling

WebAssembly-kernel

| Kernel | Wat hij uitrekent | Getallen | Getest tegen zijn tweeling |
| --- | --- | --- | --- |
| Lucht | De drukoplossing van de wind, volledige multigrid | f32 × 4 banen | **tot op de bit**, 12 roostergroottes, elke array na 150 tikken |
| Smurrie | Smurrie die tussen cellen stroomt | f64, scalair | **tot op de bit**, 10 pagina’s, elke array |
| Papier | Water, kleurstof en het opzuigen in papier | f32 × 4 banen | **binnen 10<sup>−5</sup>**, eigen pariteitstest |
| Drijvende laag | Olie en vliesjes op water | f32 × 4 banen | **binnen 10<sup>−4</sup>**, elk materiaal |
| Vuur | Warmte die zich verspreidt en branden | f64 × 2; f32 × 4 om de heetste cel te vinden | **tot op de bit**, 9 pagina’s, elk bewaard veld |
| Zeep op melk | Marangonistroming die kleur meevoert | f64, scalair | **tot op de bit**, 8 pagina’s |
| Duwen | Vingers en dingen die smurrie wegduwen | f64, scalair | **tot op de bit**, 14 pagina’s en de tegels voor het opnieuw tekenen |

Hoeveel sneller elke kernel zijn eigen simulatie maakteDuwen heeft geen SIMD en werd getimed op oliepagina’s. “smurrie, traag” is een kernel voor de trage ronde van smurrie, later weer weggehaald. De stromingskernel voor smurrie in het spel heeft geen vastgelegd getal, en er is geen tablet gemeten.

Papier werd 1,6 tot 2,9 keer sneller, de olielaag 2,2 tot 2,4, vuur 1,0 tot 1,8 en duwen 2,6 tot 2,9; de trage ronde van smurrie kwam maar tot 1,1 tot 1,2.

- minst, over de scènes
- meest, over de scènes

Gegevenstabel

Hoeveel sneller elke kernel zijn eigen simulatie maakte

|  | minst, over de scènes | meest, over de scènes |
| --- | --- | --- |
| papier | 1,6 | 2,9 |
| olielaag | 2,2 | 2,4 |
| vuur | 1,0 | 1,8 |
| duwen | 2,6 | 2,9 |
| smurrie, traag | 1,1 | 1,2 |

Bron: Tijden op de computer, elke kernel tegen zijn eigen JavaScript-lus op dezelfde pagina’s, gemeten toen hij werd overgezet.

### Een kernel blijft alleen als hij zijn plek verdient

Elke kernel werd getimed tegen zijn eigen JavaScript-lus op dezelfde pagina. Papier werd 1,6 tot 2,9 keer sneller, de drijvende laag 2,2 tot 2,4. Vuur won het minst, 1,0 tot 1,8, omdat zijn exacte doubles maar twee banen toelaten en veel cellen trage paden nemen. De duwkernel heeft helemaal geen SIMD en won toch 2,6 tot 2,9 keer.

De regel was een kernel alleen te houden bij 1,2 keer of beter op zijn eigen simulatie. Een WebAssembly-kopie van de trage ronde van smurrie \(intrekken, vlekken, smelten\) kwam tot 1,1 tot 1,2 en werd weer weggehaald. Elk getal hier komt van een computer; er zijn geen metingen van de kernels op een tablet vastgelegd.

### Eén geheugen, tot op de byte gepland voor de eerste streek

Zes van de kernels delen één blok geheugen met de JavaScript. De hoogte van de smurrie, het water en de temperatuur staan daar één keer, en elke kernel en elke JavaScript-lus leest dezelfde getallen ter plekke. Als de vuurkernel een cel verwarmt, ziet de smurriekernel dat meteen, zonder dat er iets wordt gekopieerd of een bericht wordt verstuurd.

Dat geheugen wordt vooraf uitgerekend uit wat elke kernel zegt nodig te hebben, en het groeit nooit. Als een telefoon er geen ruimte voor heeft, bouwt het spel de pagina opnieuw op met minder kernels, en zo nodig met geen.

[Onder de motorkap: één geheugen](<#hood-heap>)

Eén geheugen, tot op de byte gepland voor de eerste streek

Onder de motorkap

### Eén geheugen, tot op de byte gepland voor de eerste streek

Elke kernel geeft aan welke gedeelde velden hij leest en hoeveel kladruimte hij nodig heeft. Een veld dat door meerdere kernels wordt gelezen, wordt één keer geplaatst, en het hele plan wordt voor de grootte van de pagina gemaakt voor de eerste streek. Het geheugen wordt op zijn volle grootte gemaakt en groeit nooit, omdat het laten groeien van een WebAssembly-geheugen elke weergave losmaakt die de JavaScript erop heeft. Een automatische test houdt het gebruikte geheugen tot op de byte aan het plan, op 15 paginagroottes, en controleert dat groeien mislukt.

De meeste drukste velden van de pagina staan in dit gedeelde geheugen, en de meeste daarvan worden door twee of meer kernels gelezen. Zeldzamere lagen blijven gewone JavaScript-arrays. Elke poging met een kleiner stel kernels bouwt de wereld opnieuw op, zodat er nooit geheugen wordt vastgehouden voor kernels die niet draaien. De constanten van elke kernel hebben een eigen ruimte, toegevoegd nadat de tabellen van één kernel in een test die van een andere hadden overschreven.

## Delen van de pagina waar niets beweegt, krijgen af en toe alleen een snelle controle

Het papier is een rooster van maximaal 512 × 384 cellen, elk ongeveer een halve millimeter breed. Het spel snijdt het in kleine vierkantjes, 768 op een grote pagina. Elke soort simulatie beslist voor elk vierkantje of er iets aan de hand is. Een vierkantje opgedroogde verf of kaal papier rust, en krijgt af en toe alleen een snelle blik, vaker bij smurrie die net tot rust is gekomen dan bij een leeg vierkantje. Alleen de delen van de pagina bijwerken die veranderden, is een bekende truc van vallendzandspellen <sup>[Purho 2019](<https://professoroops.com/binnenin/onderzoek-simulatie/#purho-2019>)</sup>; hier is het een beetje boekhouding per vierkantje die de simulaties in tegels delen.

Als meer vierkantjes werk willen dan een ronde kan betalen, kiest de klok van elke simulatie de vierkantjes voor deze ronde. Die onder de hand gaan eerst. Daarna komt elk vierkantje dat te lang heeft gewacht, wat er verder ook gebeurt. De rest komt om de beurt. Een vierkantje dat wachtte, wordt niet vergeten: het hoort hoeveel rondes het miste en haalt die in met één langere stap, tot een grens die de stap stabiel houdt.

Elk proces haalt op zijn eigen manier in. Een vlek die naar de kleur van zijn smurrie kruipt, gaat met de stappen die de gemiste bezoeken zouden hebben gezet, dus hij schiet nooit door. Eiwit stolt bij elk bezoek met een zekere kans, dus het spel trekt één willekeurig getal, rekent uit bij welk gemist bezoek het zou zijn gestold, en speelt de bezoeken daarvoor als rauw en de rest als gaar.

Vuur gaat verder. Een vierkantje waarvan de warmte, de buren, de smurrie en het materiaal precies zo binnenkomen als bij de vorige stap, en dat koel en rustig is, houdt het antwoord van de vorige stap. Op een warme pagina met deeg slapen 680 van de 768 vuurvierkantjes, voor 4,6 keer minder vuurwerk, en de pagina komt er tot op de bit identiek uit.

[Onder de motorkap](<#hood-tiles>)

Delen van de pagina waar niets beweegt, krijgen af en toe alleen een snelle controle

Onder de motorkap

### Delen van de pagina waar niets beweegt, krijgen af en toe alleen een snelle controle

Er lopen zes klokken, één voor elke ronde in tegels: het stromen van smurrie en zijn trage lokale werk, het stromen en het lokale werk van de drijvende laag, en de twee rondes van het papier. Elke klok onthoudt voor elk vierkantje wanneer het voor het laatst werd bijgewerkt en hoe lang het heeft gewacht. Als meer vierkantjes werk willen dan een ronde toelaat, kiest hij in drie stappen:

- **De hand.** Vierkantjes onder de hand gaan eerst, al zijn het er nooit zoveel dat de deadline geen ruimte meer heeft. Vierkantjes bij de hand en in haar kielzog krijgen een deel van de ronde, wie het langst wacht eerst.
- **De deadline.** Elk vierkantje dat zo lang heeft gewacht als de klok toestaat, gaat, zo nodig boven het budget. Een eigenschapstest met een vast startgetal draait 60 willekeurige pagina’s, budgetten en handen elk 500 rondes lang en vindt geen vierkantje dat langer wacht dan die grens.
- **De beurt.** De rest gaat in blokken van ongeveer één ronde groot. Elke beurt begint op een nieuwe, door elkaar gehusselde plek op de pagina en loopt zijn blokken af in een wisselende richting, zodat geen rand van de pagina altijd als laatste komt.

Een vierkantje dat te laat is, zet de rondes die het miste in één keer, tot een grens; de traagste soorten werk krijgen een langere. Lange stappen kunnen niet ontsporen, omdat de stromingen worden begrensd tot wat stabiel is. Een begrensd vierkantje meldt dat, zodat een tegengehouden plas nooit wordt aangezien voor een rustige, en een test controleert het. De kans van eiwit wordt uitgespeeld vanuit één willekeurige trekking: de kans dat het in *n* bezoeken met elk kans *p* minstens één keer stolt, is 1 − \(1 − *p*\)<sup>*n*</sup>, en dezelfde trekking zegt bij welk bezoek. Op een stoltemperatuur gehouden komt het deel dat stolt, bezoek voor bezoek en in één keer overeen, vastgelegd in een test.

De grenzen zijn gemeten. Een kortere grens op het papier liet een laag waterverf na 30 s 11% natter; met de grens die het spel gebruikt, 0,7%. Een ketchupvlek op het laagste detail ging van 31% naar 89,5% van de snelheid op vol tempo na 6 s, toen het trage lokale werk zijn langere grens kreeg. Vuur slaapt alleen waar het koel en rustig is, en wordt regelmatig wakker om te controleren. Zeven pagina’s die met slapen aan en uit draaien, komen in elk bewaard veld overeen.

Probeer het: een pagina vol verf op een trage tablet De eigen regel van het spelElk vierkantje hier wil werk, zoals op een pagina vol bewegende verf. Dit is de eigen tegelklok van het spel, overgezet voor vierkantjes die werk willen \(de blikken op rustige vierkantjes zijn weggelaten\): eerst de hand, dan de deadline, dan de beurt. Elk vierkantje laat een rimpeling van kleur zien op de tijd die het heeft ingehaald, dus een vierkantje dat wachtte, laat een oudere rimpeling zien. Vierkantjes met een gele rand worden deze ronde bijgewerkt; een rood hoekje betekent dat het langer wachtte dan de grens en de rest verloor. Het draait trager dan het spel, zodat je het kunt volgen. **Probeer:** zet de volgorde op **rijen** en kijk hoe een band over de pagina veegt; druk en sleep om een hand neer te leggen \(of zet **Een hand in het midden** aan\) en zie dat haar vierkantjes nooit wachten; kies de grote pagina op detail 4 en kijk hoe er tijd verloren gaat, en dan de telefoonpagina, waar dat niet gebeurt.

![Een pagina met tegels die allemaal werk willen, bijgewerkt door de tegelklok van het spel: tegels rimpelen van kleur op de tijd die ze hebben ingehaald, de tegels die deze ronde worden bijgewerkt hebben een rand, en tegels die tijd verloren voorbij de grens krijgen een rood hoekje. Druk en sleep om een hand neer te leggen.](<https://professoroops.com/_assets/entity_ru6Cpvjd67WtgSWcF3l5.png>)

Detail0 · 1601 · 1002 · 603 · 364 · 20Pagina288 × 216384 × 288512 × 384Volgordeblokkenrijen

tegels per ronde—

tegels op de pagina—

een beurt—

stap van een tegel—

langste wachttijd nu—

tijd verloren voorbij de grens—

Rondes tot elk vierkantje van een drukke pagina een beurt krijgtPagina’s: 252 vierkantjes op de 288 × 216 van een telefoon, 300 klein, 432 middel, 768 groot. Boven de gestreepte lijn verliest een pagina vol bewegende verf tijd. Op het laagste detail op een grote pagina duurt een beurt ongeveer twee derde seconde.

Op het laagste detail kost een grote pagina van 768 vierkantjes 38,4 rondes per beurt, voorbij de inhaalgrens van 16; een telefoonpagina van 252 kost 12,6. Op het rijkste detail kost elke pagina minder dan 5.

- rijkste detail
- middelste detail
- laagste detail
- inhaalgrens

Gegevenstabel

Rondes tot elk vierkantje van een drukke pagina een beurt krijgt

| vierkantjes op de pagina | rijkste detail | middelste detail | laagste detail | inhaalgrens |
| --- | --- | --- | --- | --- |
| 252 | 2 | 4 | 13 | 16 |
| 300 | 2 | 5 | 15 | — |
| 432 | 3 | 7 | 22 | — |
| 768 | 5 | 13 | 38 | 16 |

Bron: Rekenwerk uit de detailniveaus van het spel: de vierkantjes op de pagina gedeeld door de vierkantjes die een ronde mag nemen, tegenover de inhaalgrens.

![Het verborgen debugpaneel van het spel met zijn tegelkaart over een pagina vol strepen verf op het laagste detail, midden in een streek: oranje vierkantjes waar de verf deze ronde werd bijgewerkt en blauwe waar het papier dat werd, in een paar blokken over de pagina en een groepje rond de hand.](<https://professoroops.com/_assets/entity_VhpLANvAx1tzEQRzFMgP.webp>)

**Het echte spel, midden in een streek op het laagste detail.** De eigen debugkaart van het spel licht de vierkantjes op die deze ronde worden bijgewerkt, oranje voor de verf en blauw voor het papier: een paar blokken van de beurt, en de vierkantjes rond de hand, die eerst gaan.

![De kaart van het debugpaneel die laat zien hoe ver elk vierkantje achterloopt, op een pagina vol gele verf op het laagste detail, een seconde nadat de vinger losliet: rechthoekige blokken van geel \(net bijgewerkt\) via oranje naar rood \(zo lang gewacht als de grens toestaat\), het grootste deel van de onderste helft rood.](<https://professoroops.com/_assets/entity_JnqDLsZp6SbMZnFZu6qq.webp>)

**Hoe lang elk vierkantje heeft gewacht.** Een seconde nadat de vinger loslaat, liggen de wachttijden in rechthoekige blokken die de beurt heeft neergelegd: gele vierkantjes zijn net bijgewerkt, rode hebben zo lang gewacht als hun grens toestaat. Op het laagste detail vraagt deze pagina meer dan een ronde kan geven, dus is veel ervan rood, en daar wordt tijd losgelaten.

## Als de tijd krap is, gaat de hand eerst

Op een apparaat dat het bijhoudt, kiest het spel een detailniveau en houdt dat vast zolang het past. Als stappen te lang beginnen te duren, gaat het snel een niveau lichter. Als er ruim tijd is, gaat het langzaam een niveau rijker. Snel omlaag, langzaam terug.

Op een apparaat dat het spel als traag heeft gemeten, of een waarvan de beelden steeds te lang duren, verdeelt het in plaats daarvan de tijd van elk beeld. Het mikt op 30 beelden per seconde, of 60 als dat met ruimte past. Het werk dat moet gebeuren, gaat eerst: de simulaties die niet in vierkantjes zijn gesneden, de vierkantjes onder de hand en het versturen van plaatjes naar het scherm. De achtergrond houdt altijd een gegarandeerd deel van het beeld, zodat hij nooit stopt met inhalen, en het duwen van de hand zelf houdt ook een deel.

Zolang er een hand op de pagina ligt, krijgt de achtergrond zijn gegarandeerde deel en niet meer. Het beeld is eerder klaar, en wat de hand doet, verschijnt eerder. Wat “onder de hand” is, is met opzet ruim: elke vinger, een ding dat over de pagina glijdt, een ding dat landt, een uitbarsting. Ze markeren allemaal één gedeelde kaart, die alle zes de klokken lezen.

Een zwaar beeld wordt in plakjes van een paar milliseconden gesneden, en de worker neemt tussendoor nieuwe aanrakingen op. Een plakje eindigt bij de volgende natuurlijke pauze in een stap, dus een lang deel kan uitlopen, maar een aanraking hoeft niet meer op een heel beeld te wachten.

[Onder de motorkap](<#hood-hand>)

Als de tijd krap is, gaat de hand eerst

Onder de motorkap

### Als de tijd krap is, gaat de hand eerst

De planner begint met een schatting van wat elke soort werk kost en meet het daarna, waarbij hij een stijging snel gelooft en een daling langzaam. De tijd van elk beeld wordt verdeeld in volgorde van noodzaak: wat moet gebeuren, de vierkantjes van de hand, het duwen van de hand, dan de achtergrond, met een gegarandeerde bodem voor zowel de achtergrond als het duwen. Een kleine terugkoppeling stelt het budget bij naar hoe lang recente beelden echt duurden.

De tijd van de achtergrond wordt verdeeld over het stromen, het trage lokale werk en het papier met één gemeenschappelijke maat: hoeveel verandering elk vierkantje nog tegoed heeft, zwaarder gewogen bij de hand. De soort werk die het meest moet inhalen, krijgt de meeste vierkantjes. Dit bepaalt hoeveel vierkantjes, nooit welke: de klokken gaan nog steeds op hand, deadline en volgorde.

De focus van de hand werkt als warmte. Een vierkantje onder een aanraking is heet, en die warmte ebt stap voor stap weg. De heetste vierkantjes gaan eerst, dan een ring eromheen, dan het recente kielzog met een lagere voorrang. Er passen maar zoveel stappen in een beeld; daarboven loopt de tijd langzamer en wordt dat geteld.

Vijf detailniveaus veranderen hoeveel vierkantjes er per ronde gaan en hoe vaak trager werk draait. Ze veranderen nooit de grootte van een cel. Gloeiende sintels zijn natuurkunde en blijven even talrijk op elk apparaat; alleen deeltjes die puur voor het oog zijn, worden dunner.

Probeer het: waar de tijd van één beeld heen gaat De eigen regel van het spelDe balk is één beeld, verdeeld volgens de eigen regel van het spel. De gestreepte lijn is het doel \(1/60 of 1/30 s\), gekozen met een vereenvoudigde vorm van de regel van het spel. Voor het plaatje zijn de tegels onder de hand op negen gezet. De tijd die elk deel kost, staat onder de balk. **Probeer:** til de hand op en kijk hoe de achtergrond neemt wat vrij is; maak het apparaat trager en kijk hoe het doel zakt naar 30 beelden per seconde; duw harder en kijk hoe het duwen van de hand stopt bij zijn deel, en de rest wacht op de volgende beelden.

![Eén beeld getekend als een balk, verdeeld over de vaste simulaties, de tegels onder de hand, het duwen van de hand, de achtergrondtegels, het inpakken en de replica, tegenover een gestreepte lijn voor de beoogde beeldtijd.](<https://professoroops.com/_assets/entity_Y2GtUdYTQx45ayxDRzSo.png>)

- Eén beeld bij 60 beelden per seconde, 1 stap
- Eén beeld bij 30 beelden per seconde, 2 stappen
- doel
- budget B
- over
- boven het doel
- vaste simulaties
- tegels van de hand
- duwen van de hand
- achtergrondtegels
- inpakken
- replica

Apparaat1,0× trager

Duwen van de hand2,00 ms

beeld—

doel—

budget B—

vaste simulaties—

tegels van de hand—

duwen van de hand—

achtergrondtegels—

achtergrond, tegelbezoeken per stap—

inpakken—

replica—

duwen bewaard voor latere beelden—

Levende beelden rond de hand, van een streek van 44 beeldenKetchup: gemiddelde over tien streken, 40 tot 44; de test eist minstens 41. Olie: de grens van de test, minstens 35. De getallen van “eerst” komen uit de notities bij de test.

Bij het uitsmeren van ketchup waren 19 beelden levend voordat de hand voorrang kreeg en nu 42,3; met een hand in olie op water 28 eerst en nu minstens 35.

- voordat de hand voorrang kreeg
- nu

Gegevenstabel

Levende beelden rond de hand, van een streek van 44 beelden

|  | voordat de hand voorrang kreeg | nu |
| --- | --- | --- |
| ketchup uitsmeren | 19,0 | 42,3 |
| hand in olie op water | 28,0 | 35,0 |

Bron: Een automatische test op het laagste detail op een pagina van 320 × 240.

### Getest op het traagste detail

Een test smeert ketchup over een pagina van 320 × 240 op het laagste detail en telt de beelden waarin de streek minstens een kwart zoveel cellen bij de hand veranderde als hij zonder enige grens zou doen. Voordat de hand voorrang kreeg, waren 19 beelden van een streek van 44 beelden levend. Nu zijn het er ongeveer 42. Met een hand in olie op water stegen de levende beelden van 28 naar minstens 35, en onder de hand misten de smurrie, de olie en beide papierklokken geen van de rondes die ze wilden.

De hand alles geven is ook geprobeerd. Met een hele ronde voor de hand wachtte het vliesje olie over de rest van de pagina zo lang dat het treden rond de streek achterliet, 1,71 tegenover 1,63 met een deel, en de deadline moest over het budget heen. Dus de hand krijgt een deel, en de rest van de pagina houdt wat overblijft.

## Elk apparaat meet zichzelf en krijgt een paginaformaat dat het kan dragen

Bij de eerste keren opstarten, na een update en daarna af en toe meet het spel stilletjes zichzelf. Op een moment dat er niets gebeurt, draait een wegwerpworker de echte simulaties op een kleine, drukke kladpagina: zes plassen verf, een doorweekt rondje kleurstof, twee vuurtjes, confetti, glitter en een hete föhn. Een snel apparaat krijgt een pagina van 512 × 384, een middelmatig 384 × 288, een traag 320 × 240. Het kleine scherm van een telefoon stelt een eigen grens, tot 288 × 216.

Een kleinere pagina maakt de kwasten of de dieren niet kleiner. Alles wordt in cellen gemeten, dus een kleinere pagina laat alles een beetje groter en grover zien. Een pagina houdt het formaat waarop hij is getekend; een nieuw formaat geldt alleen voor een nieuwe pagina.

De regel is royaal naar boven en voorzichtig naar beneden. Eén goede meting verhoogt het formaat; er zijn een paar slechte achter elkaar nodig om het te verlagen. Als een tablet een paar lange sessies achter elkaar vooral op de laagste detailniveaus speelt, komt de volgende nieuwe pagina één maat kleiner.

[Onder de motorkap](<#hood-size>)

Elk apparaat meet zichzelf en krijgt een paginaformaat dat het kan dragen

Onder de motorkap

### Elk apparaat meet zichzelf en krijgt een paginaformaat dat het kan dragen

De meting draait dezelfde engine waarmee het spel speelt, de kernels inbegrepen, op een kladpagina die klein genoeg is dat alles elke stap wordt bijgewerkt. Een meting is een handvol korte runs. De eerste wordt weggegooid als opwarmer en de **beste** van de rest wordt gehouden, omdat druk zijn met iets anders een run alleen maar trager maakt. Op een apparaat met weinig kernen zet hij alleen stappen terwijl de eigen simulatie van de tafel slaapt, en een vinger breekt de run af.

Het opgegeven geheugen en het aantal kernen begrenzen het formaat voordat er iets wordt gemeten. De grenzen hebben een marge naar beide kanten, zodat een apparaat dat dicht bij een grens zit, niet heen en weer springt. De pagina is nooit groter dan het scherm nodig heeft, en een volwassene kan het formaat in de instellingen overschrijven.

Waarom het ertoe doet: op een grote pagina op het laagste detail duurt één beurt over een hele pagina langer dan de inhaalgrens, dus een rommel over de hele pagina verliest daar tijd. Op een kleine pagina past de beurt binnen de grens. Kort na het eerste beeld warmen de simulaties ook in stille tijd op op een kladpagina, zodat de browser ze heeft geoptimaliseerd voor de eerste grote rommel.

Waar de score van een apparaat zijn paginaformaat verschuift IllustratieDe vorm van de regel van het spel: elke grens heeft een marge naar beide kanten, dus een pagina gaat een maat omlaag een eindje erna en een maat omhoog een eindje ervoor. Omlaag vraagt een paar metingen achter elkaar; omhoog één. **Probeer:** schuif het apparaat trager voorbij een grens en weer terug: de pagina houdt zijn kleinere formaat tot het apparaat duidelijk sneller is. Op de schuif staat elke stand voor genoeg metingen, en de schaal heeft geen eenheden: hij laat de vorm van de regel zien, niet de getallen.

![Een schaal van hoe lang een apparaat over één stap doet, van snel links tot traag rechts, verdeeld in een grote, een middelgrote en een kleine pagina. Een pagina gaat een maat omlaag een eindje voorbij elke grens en een maat omhoog een eindje ervoor, zodat een apparaat bij een grens niet heen en weer springt.](<https://professoroops.com/_assets/entity_JwePgLbS6fcFOOaOcQCn.png>)

- groot
- 512 × 384
- middel
- 384 × 288
- klein
- 320 × 240
- snel
- traag
- tijd voor een stap
- maat omlaag
- maat omlaag
- maat omhoog
- maat omhoog

Tijd voor een stap, snel tot traag30

de volgende nieuwe pagina—

### Twee uur wachten komt op elk detailniveau hetzelfde uit

Met de tijdknoppen kan een kind vooruitspringen terwijl verf droogt of deeg rijst. Een sprong negeert alle rantsoenering hierboven. Hij werkt hetzelfde aantal vierkantjes per ronde bij, welk apparaat het ook is, wist de focus van de hand en duurt langer op een trage tablet. Een test wacht twee uur op drie pagina’s \(verf, olie, ketchup\) op detail 0, 2 en 4 en krijgt dezelfde pagina, op 18 velden. Hiervoor liet een sprong van drie uur bij het budget van een trage tablet verf 7% en olie 16% minder ver uitgevloeid achter.

Een sprong speelt de uren niet stap voor stap af. Vloeibare dingen krijgen per uur een vast aantal stromingsrondes, tot een grens, en de rest wordt per cel met formules uitgerekend, zoals een gesloten vorm voor drogen. De sprong draait in korte plakjes, zodat het scherm blijft leven, en een streek die intussen wordt getekend, komt erna op het vel.

[Onder de motorkap: sprongen in de tijd](<#hood-skip>)

Twee uur wachten komt op elk detailniveau hetzelfde uit

Onder de motorkap

### Twee uur wachten komt op elk detailniveau hetzelfde uit

Een sprong is een taak die tussen elke twee stukjes werk kan stoppen en weer verdergaan, zodat hij de worker nooit lang vasthoudt. Reacties over de overgeslagen tijd volgen de vuistregel van scheikundigen dat een snelheid ruwweg verdubbelt bij elke 10 °C warmer \(Q10 = 2\). Eén test vergelijkt een vingerafdruk van 18 velden op drie detailniveaus, op één machine met de JavaScript-lussen. Een andere snijdt bakken in de oven en wachten in de fijnste plakjes, met tikken ertussen, en krijgt elk veld, en het volgende willekeurige getal, gelijk aan alles in één keer. Twee echte apparaten worden niet vergeleken: paginaformaten verschillen, en de wiskundige functies van browsers kunnen in het laatste cijfer verschillen.

### Ongedaan maken houdt alleen de vierkantjes bij die veranderden

Ongedaan maken bewaarde vroeger hele kopieën van de pagina. Nu houdt elke oudere stap alleen de vierkantjes bij die verschillen van de stap erna, en een leeg vierkantje kost bijna niets. Na vier streken en een overstroming ging ongedaan maken op een computerpagina van 144 MB naar 17 MB, en op een telefoonpagina van 46 MB naar 6,6 MB.

Dus ongedaan maken gaat zo ver terug als een vast geheugenbudget toestaat, met een bodem en een plafond voor het aantal stappen: ongeveer 65 streken op een droge pagina van 384 × 288 en 11 op een natte.

Geheugen voor ongedaan maken na vier streken en een overstromingEen automatische test houdt het onder een derde van hele kopieën, met opzet een lage lat.

Op een computerpagina ging ongedaan maken van 144 MB met hele kopieën naar 17 MB met verschillen per vierkantje; op een telefoonpagina van 46 MB naar 6,6 MB.

- hele kopieën \(eerst\)
- verschillen per vierkantje \(nu\)

Gegevenstabel

Geheugen voor ongedaan maken na vier streken en een overstroming

|  | hele kopieën \(eerst\) | verschillen per vierkantje \(nu\) |
| --- | --- | --- |
| computerpagina | 144,0 | 17,0 |
| telefoonpagina | 46,0 | 6,6 |

Bron: Gemeten met een benchmark van vier streken en een overstroming.

[Ongedaan maken, onder de motorkap](<#hood-undo>)

Ongedaan maken, onder de motorkap

Onder de motorkap

### Ongedaan maken, onder de motorkap

Alleen de nieuwste stap wordt heel bewaard; oudere stappen houden de vierkantjes bij die verschillen. Vierkantjes worden bit voor bit vergeleken, zodat elke waarde, zelfs min nul en not-a-number, precies terugkomt, en een test legt dat vast. Als het grootste deel van een veld veranderde, wordt de oude kopie in zijn geheel overgedragen in plaats van gekopieerd. De binnenste lussen zijn één keer geschreven voor elk soort getal dat ze verwerken, omdat een lus die meer dan één soort array ziet ongeveer half zo snel draait. Een momentopname maken met elk veld veranderd ging van 24 naar 12 ms.

## Ideeën die sneller klonken, zoals de grafische chip gebruiken, zijn getest en geschrapt

Snelheidswerk zit vol ideeën die sneller klinken. Elk idee hier is gebouwd en gemeten tegen wat er al was. Dit zijn de ideeën die het niet haalden, met wat de meting zei.

| Het idee | Wat de meting zei | Uitkomst |
| --- | --- | --- |
| Het papier en de smurrie op de grafische chip draaien | Tegenover WebAssembly op de hoofdthread haalde het 25 tot 70% van een beeld met verf of water af, en niets bij het drukste. De worker deed het in elke scène al even goed of beter, zonder 3 tot 4 ms extra GPU-tijd per beeld \(Chrome op de computer\). Een derde kopie van de logica niet waard. | Weggelaten |
| Begrensde tijd terugbetalen met extra deelrondes | Gebouwd en getest. Op het laagste detail, op pagina’s met olie, vliesjes, ketchup en uitsmeren, lagen het gemiddelde beeld en het traagste op twintig binnen een paar procent naar beide kanten. | Uitgezet |
| Een hele ronde aan de hand geven | De olie over de rest van de pagina wachtte zo lang dat ze treden rond de streek achterliet, 1,71 tegenover 1,63 met een deel, en de deadline ging over het budget heen. | In plaats daarvan een deel |
| Om de andere beurt achterstevoren over de pagina gaan | Vierkantjes aan de uiteinden wachtten twee beurten en dan geen; met een korte grens kregen ze maar 53 tot 97% van hun tijd terug. | In plaats daarvan blokken |
| Steeds minder vaak naar rustige smurrie kijken | Ze raakte achter bij haar buren en de trede ertussen stond recht langs de rand van het vierkantje, 3,5 tegenover 2,8. | Een vast ritme |
| De wind op het papier om de beurt in stukken bijwerken | Naden, vlekken of korrel. Banden langs de wind vervingen ze, en een test houdt de naden binnen de grenzen. | In plaats daarvan banden |
| WebAssembly voor de trage lokale ronde van smurrie | 1,1 tot 1,2 keer sneller, onder de 1,2 waar de regel om vraagt. | Teruggedraaid |
| Een eerste kernel voor staand water | 1,0 tot 1,15 keer, slechter op dunbezette tegels. Waterkernels kwamen later in een andere vorm. | Toen geschrapt |

Wat niet is gemeten, telt net zo zwaar. Er zijn geen tijden van de kernels op een echte tablet vastgelegd, geen gemeten totaal geheugen van een draaiende pagina, en geen vastgelegde vertraging van aanraking tot scherm. Veel hiervan is getest op een computer die zich als een traag apparaat moest gedragen: een ontwikkelschakelaar laat de worker meerdere keren zo lang bezig-wachten en schaalt de kosten die hij meet, zodat de planner het apparaat ziet waarvoor hij bedoeld is. Daarom kon er zoveel worden getest zonder tablet, en daarom is er toch nog een nodig.

## Elk gereedschap krijgt de snelheidstrucs er gratis bij

Niets van de machinerie hier weet iets van ketchup of kaarsen. Ze leest dezelfde gedeelde markeringen die elke simulatie schrijft, dus een nieuw gereedschap heeft geen plannercode nodig.

Gedeeld: één gedeelde kaart van de hand, gelezen door zes klokken

### Smeer verf uit op een pagina vol verf, op een trage tablet

Onder de hand missen smurrie, olie en beide papierrondes geen ronde die ze willen, en een test controleert het.

[Dun, plakkerig en vettig](<https://professoroops.com/binnenin/vloeistoffen/>)

Gedeeld: vuur onthoudt wat er bij de vorige stap binnenkwam

### Laat een warme pagina met deeg met rust

680 van de 768 vuurvierkantjes slapen en de pagina komt er tot op de bit hetzelfde uit, vastgelegd in een test.

[Warmte en vuur](<https://professoroops.com/binnenin/warmte/>)

Gedeeld: een gedeelde markering van wat veranderde

### Laat een natte pagina drogen

Alleen de plaatjes van pigment en water worden opnieuw verstuurd, niet de smurrie of de hoogte, en een test controleert het.

[Licht en schaduw](<https://professoroops.com/binnenin/licht/>)

Gedeeld: de drijvende laag, en dan de lagen die zich zetten

### Laat water onder olie op het papier kruipen

De olie drijft erop omhoog, met de kernel voor de drijvende laag en zonder; het kernelhek controleert beide.

[Water in papier](<https://professoroops.com/binnenin/water/>)

Gedeeld: het deel van het beeld voor de lucht

### Blaas met de föhn over nat papier op een traag apparaat

De wind werkt in banden langs zijn eigen richting, en een test houdt de naden binnen de grenzen.

[Lucht die echt beweegt](<https://professoroops.com/binnenin/lucht/>)

Gedeeld: een sprong in één vast tempo, de focus van de hand gewist

### Wacht twee uur nadat je verf en olie hebt gemorst

Dezelfde pagina op drie detailniveaus, vastgelegd in een test.

[Deeg, schimmel en tijd](<https://professoroops.com/binnenin/levend/>)

7

WebAssembly-kernels, elk naast zijn JavaScript-tweeling gehouden en ertegen getest.

0 bits

Verschil tussen de luchtkernel en zijn JavaScript-tweeling, op 12 roostergroottes. Probeer het hierboven.

19→42

Levende beelden van 44 rond een hand die ketchup uitsmeert op het laagste detail, gemeten in een test.

4.6×

Minder vuurwerk op een warme pagina met deeg, waar 680 van de 768 vierkantjes slapen.

2.9×

De grootste versnelling die een kernel zijn eigen simulatie gaf, gemeten op een computer.

144→17 MB

Geheugen voor ongedaan maken na vier streken en een overstroming op een computerpagina.

## Waar we vereenvoudigen, en waarom

Elke truc op deze pagina ruilt iets exacts in voor iets wat een tablet kan betalen. Hier is elke ruil, en wat hij kost.

**In het echt.** Tijd stroomt overal tegelijk

**In het spel.** Vaste stappen van 1/60 s; het papier en het trage lokale werk op de helft van dat tempo, om de andere tik; op een traag apparaat zetten vierkantjes op verschillende momenten stappen en halen ze in met één langere stap, tot een grens.

**Waarom dat genoeg is.** Begrensd werk per beeld. Buren die een ronde uit elkaar liggen, laten een flauwe trede achter aan de randen van vierkantjes: op een trage pagina met olie op water 1,15× tot 1,6× de treden binnen vierkantjes, tegenover 1,1× tot 1,4× zonder grens.

**In het echt.** Een stuk verf dat achterloopt, zou al zijn tijd terug moeten krijgen

**In het spel.** Het krijgt tijd terug tot een stabiliteitsgrens \(een langere voor de olielaag en het trage lokale werk\); de rest valt weg en wordt geteld. Een begrensde lange stap doet minder dan waar hij voor staat.

**Waarom dat genoeg is.** Stabiliteit eerst. Een rommel over de hele pagina op het laagste detail op een grote pagina verliest wel tijd, en daarom krijgen trage apparaten kleinere pagina’s.

**In het echt.** De klok loopt in echte tijd

**In het spel.** Maar zoveel stappen per beeld; daarboven loopt de tijd iets te langzaam en wordt dat geteld.

**Waarom dat genoeg is.** Beter dan een spiraal waarin elk laat beeld het volgende later maakt.

**In het echt.** De dubbele precisie van de JavaScript

**In het spel.** De kernels voor papier en de drijvende laag werken in 32-bitsbanen.

**Waarom dat genoeg is.** Vier banen in plaats van twee. De afronding blijft onder 10<sup>−5</sup> en 10<sup>−4</sup>.

**In het echt.** Het scherm laat het heden zien

**In het spel.** Eén beeld achter op de simulatie; op een traag apparaat worden vierkantjes binnen een budget geüpload, die van de hand eerst, en elk vierkantje dat te lang moest wachten, gaat voor.

**Waarom dat genoeg is.** De vinger wordt nooit geblokkeerd. Een verre hoek kan er een paar beelden oud uitzien, langer als het uploadbudget krap is.

**In het echt.** “Zichtbare verandering” is wat een oog opmerkt

**In het spel.** De eigen rustdrempel van elke simulatie is de eenheid, en de pagina is óf zichtbaar óf verborgen.

**Waarom dat genoeg is.** Goedkoop en vergelijkbaar tussen simulaties. Het is een vervanging, nooit getest tegen het menselijk zien.

**In het echt.** Stille warmte blijft een beetje veranderen

**In het spel.** Vuur hergebruikt het resultaat van de vorige stap waar niets anders binnenkwam; op de twee laagste niveaus slaan sommige rustige vierkantjes ook om de andere stap over.

**Waarom dat genoeg is.** Slapen verandert niets, tot op de bit. Overslaan kost op een pagina met een föhn hooguit 2 tot 3 °C.

**In het echt.** Hoe snel een apparaat is

**In het spel.** Eén getal, de beste van een paar korte runs van één vaste scène.

**Waarom dat genoeg is.** Stabiel op een druk apparaat. Het ziet de kosten van de graphics niet, of een tablet die na verloop van tijd warm wordt; het speelverslag dekt daar een deel van.
