Submitted:
17 October 2026
Posted:
20 October 2026
You are already at the latest version
Abstract
Most of the 135 million users registered with Scratch by July 2024 were children, and the tools that grade, test and rank their games replay them in a browser, assuming that a program under the same inputs ends the same way in every browser. For one popular game in fourteen it does not: a game that works at home can end differently when the teacher grades it on another computer. The main cause is how Scratch tests touching: it compares collision outlines that the browser rasterizes and that Scratch keeps at the largest scale drawn so far, so the browser, the screen and the computer are hidden inputs of every game that tests touching with a vector costume. Our replay, built on Scratch's own virtual machine and renderer, fixes the keys, the random numbers and the clock, can pin the browsers' arithmetic, and names the first pixel test whose answer differs. We prove that browsers that draw every edge within a pixel can disagree about touching only near contact, and we give a fix: one outline per costume, drawn at a fixed scale by one portable rasterizer. We replayed 500 popular Scratch games, chosen before any evaluation run, for ten seconds of scripted play. Of the 473 that use no camera or web service and finish in all three browsers, 33 (7.0%) end differently across Chrome, Safari and Firefox, and the Scratch editor itself, in release Chrome and Firefox, splits 22 of the 33. Within one browser, a sharper screen or a larger stage changes 7.0% of the games, and moving release Chrome from a Mac to Windows changes 2.5%. With the arithmetic pinned, 24 of the 28 browser splits start at a pixel test, and feeding one browser the other's renderer answers reproduces the other's ending in all 24 games tested. The fix cuts browser splits to 1.3%, and those of every other setting on one computer to at most one game.
Keywords:
Scratch
; reproducibility
; collision detection
; rasterization
; deterministic replay
; computer vision
1. Introduction
A child builds a Scratch game, tests it at home and sees it work; the teacher then grades it with the same keys on another computer, and the game ends differently. In July 2024 Scratch’s 135 million registered users, mostly children, had shared 164 million projects [32]; many learn to program in it [21,31]. Around it has grown a set of tools that judge what those programs do: test generators and test frameworks [7,11,15,35], per-assignment graders [17], hint generators that run prior solutions against tests [26], and online judges and competitions that rank submissions by what happens on the stage. All of them run the program, feed it inputs such as key presses, and read what happens, such as positions, scores and collisions. They share one assumption: the same program under the same inputs ends the same way wherever it runs.
Yet across Chrome, Safari and Firefox alone, one popular game in fourteen breaks this assumption. Figure 1 shows a public runner game: holding the space key keeps the runner hovering among flying saws, its gravity flipping; the runner earns a point every second and starts again from zero when a saw touches it. We play it for ten seconds with the same key, seed and clock, and change nothing but where it is drawn. At 4.33 s a saw’s tooth reaches the runner’s hand. Safari counts the saw as touching; Chrome does so one frame later. The two runners restart one frame apart, and at 9.60 s a later saw hits Chrome’s runner and passes over Safari’s. The game ends with 0 points in Chrome on a Mac and in release Chrome 154 on Windows, and with 5 in Safari, in Firefox and in Chrome on a sharper screen. The same child can get a different grade on a different computer, and nobody can see why.
The reason is a single block, touching. Scratch decides whether two sprites touch by testing pixels. The renderer asks the browser to draw each vector costume, keeps the drawing’s alpha channel as the costume’s collision outline, and checks whether some stage point is covered by both outlines [34]. Browsers draw the same curve with slightly different anti-aliasing, so the outlines differ along the edges. The renderer also keeps, for each costume, the largest drawing made so far, and a sharper screen or a larger stage asks for larger drawings. A touching test therefore reads pixels that the program does not control, and the browser, the screen and the computer become hidden inputs of every game that tests touching with a vector costume. One might expect edges that differ by a pixel to be harmless. They are not, because a game asks whether two sprites touch at the moment they meet, when one pixel decides the answer.
In this paper we measure how often these hidden inputs decide a game, find out why, and remove most of them. We replay each game in the editor’s own virtual machine and renderer inside a real browser, with the keys, the random numbers and the clock fixed, and vary one rendering setting at a time: the browser engine, the screen’s pixel ratio, the stage size, the graphics or canvas path, the window or the computer. Where two runs part, we name the first pixel test whose answer differs and, for a touching test, the stage points it read. A model of the renderer explains what we see. Renderers that draw every edge within of the true shape can disagree only within about of contact, and keeping the largest drawing makes touching depend on past drawings. The model also suggests a fix, which we implement and measure: draw each costume’s outline once, at a fixed scale, with one portable rasterizer.
Of 500 popular Scratch games, chosen before any evaluation run, 473 use no camera or web service and finish in all three browsers, and 33 (7.0%) of these end differently across Chrome, Safari and Firefox after ten seconds of scripted play; in release Chrome and Firefox, the editor itself splits 22 of the 33. In one browser, a sharper screen or a larger stage changes 7.0% of the games, and the same Chrome 154 build ends 2.5% of them differently on Windows than on a Mac. The browsers’ JavaScript engines also compute some Math functions differently. With this arithmetic pinned to one portable implementation, the browsers still split 5.9% of the games. Of these splits, 86% start at a pixel test, and replaying one browser with the other’s renderer answers reproduces the other’s ending in all 24 games we tried. The splits reach grades, though less often than end states: between Chrome and Safari, two tutorials’ checks change their verdict for 2.3% and 1.9% of the sampled public remixes that run them. With the fix, the browsers split 1.3% of the games and no other setting on one computer splits more than one. We make four contributions.
- A hidden input, measured. The browser, the screen, the stage and the computer each decide how popular Scratch games end, the browser one game in fourteen; the Scratch editor in release Chrome and Firefox splits 22 of the 33, and the splits change tutorial checks’ verdicts (Section 5).
- A replay that names the pixel. Built on Scratch’s own packages, it fixes the keys, the random numbers and the clock, can pin the engines’ arithmetic, names the first differing answer, and confirms, by transplanting answers, that the pixels carry the split (Section 4 and Section 5.3).
- A fix and its ablation. Two outline changes and colour tests on the CPU bring the browser splits to 1.3% of the games; the fixed scale (Step 1) removes the effect of the screen and the stage in fresh pages, the one rasterizer (Step 2) cuts most browser splits, and the rest split outside the outline (Section 5.5).
2. How Scratch Decides Touching
The Scratch editor runs a project in two parts: a virtual machine that executes the blocks one frame at a time, 30 frames a second [33], and a WebGL renderer that draws the stage [34]. The renderer answers every block that asks about pixels, the pixel tests, so its pictures are part of the program’s semantics. We follow one vector costume from the project file to a touching test’s answer in scratch-render 2.2.84, the version our replay runs.
- Loading A vector costume is an SVG file. When the project loads, the costume’s box (its size in stage units and its top-left corner) is read from the SVG’s view box; an SVG without one is inserted into the page and measured with the browser’s getBBox. Paths are measured geometrically, but text is laid out in the browser’s own fonts, so such a costume, if it holds text, can get a different size in different browsers.
- Drawing To draw a vector costume, the renderer asks the browser to paint the SVG into a 2D canvas at a power-of-two scale, a MIP, and uploads the pixels as a texture. The scale is the smallest power of two at least as large as the sprite’s size on the screen, which grows with the sprite’s size, with the stage’s size in canvas pixels and with the screen’s device pixel ratio. The same pixels, or texels, give the costume its collision outline, the alpha and colour data that the pixel tests read on the CPU. The outline is replaced only when a larger MIP is drawn; in the renderer’s own words, “silhouettes only get scaled up”. A bitmap costume’s outline is the bitmap itself.
- Testing The block touching sprite? walks every integer stage point in the intersection of the two sprites’ bounding boxes and returns true at the first point covered by both outlines. An outline covers a point when a texel sampled for it (one, or four with linear sampling) has a non-zero alpha. The blocks touching colour? and colour is touching colour? sample the outlines’ and the pen layer’s colours on the CPU when the region to check is small, and otherwise draw the candidates’ textures with WebGL and read the pixels back. If on edge, bounce and touching edge? read the sprite’s bounds, the box of the convex hull of its outline’s points. Every move is finally fenced: the renderer keeps a sprite partly on the stage using the box of its costume’s measured size.
- Where the answer comes from Each step hands a decision to the browser: its rasterizer decides which pixels an edge covers, the pixel ratio and the stage’s size how large the drawing is, and the fonts how large a costume with text and no view box is. Nothing in the project records which browser, screen or computer drew the pixels that decided a test.
3. A Model of Render-Dependent Touching
This section states when a Scratch run depends on the renderer and proves four results about it. The model abstracts the virtual machine into a step function and the renderer into the answers it gives, and takes the renderer’s behaviour from the scratch-render source traced in Section 2.
- Runs A run of a program P under inputs (the keys pressed in each frame) and seed is a sequence of states , one per frame. The state includes every costume’s measured box, whether each sprite holds a cached convex hull, and how far the random and clock streams have been read. Within a frame the virtual machine executes blocks in order, and every value it receives from outside is an answer: a random number, a clock reading, a device reading, the value of a JavaScript Math function, or the reply to a renderer query. A frame is computed by a deterministic step function , where lists the frame’s answers in order. Math values are answers because the browsers’ engines disagree on them (Section 5.3); basic arithmetic and the square root are correctly rounded in every engine and belong to F. Table 1 lists the renderer queries whose replies can reach the state.
Definition 1
(Outline). For a vector costume c and a scale k, let be the alpha mask that renderer R draws for c at scale k. The renderer draws c at a new scale whenever a texture request needs one: drawing the stage or a dragged sprite requests the sprite’s size times the canvas’s scale factor, a query answered on the CPU or a stamp requests the sprite’s own size, and a touching test or a stamp also requests the asking sprite’s costume at 100%. Each request is rounded up to a power of two and capped at the largest one at which the costume’s longer side fits in 2,048 texels, or at 1 if no larger one does. The outline of c at a query is , where is the largest scale that any sprite or clone has requested for c so far, that query’s own requests included. The outline of a bitmap costume is its own alpha channel.
Definition 2
(Touching). Visible sprites a and b touch in renderer R at a query, written , if
where is the value that sampling the outline of s’s current costume returns at stage point p, and is the box that R scans for s: the box of the convex hull of s’s outline if a bounds query or a speech bubble has computed the hull since it was last invalidated, and otherwise the box of s’s costume at its measured size, clipped to the stage and rounded out to whole stage units. The block touching X asks this for each visible among X and its clones whose box meets , with p in the box spanning these .
Definition 3
(Render-dependent program, witness). P is render-dependent for renderers R and under ι and σ if . The witness of the difference is the first answer, in the order of frames and of events within a frame, whose query both runs ask with the same arguments and whose values differ.
Lemma 1
(Replay). Let two runs of P share the inputs, the device readings, and random and clock streams whose next value depends only on the values drawn before it and on the frame. If and every renderer andMath answer in frame t has the same value in both runs, then . Hence, if two such runs start from the same and differ, a witness exists, and it lies in or before the first frame whose states differ.
Proof.
Equal states have read the streams equally far, so within the frame the two runs execute the same events in the same order and read the same stream values; with equal renderer and Math answers, and F gives equal results. For the second claim, take the first event, in the order of frames and of events within a frame, at which the runs differ: everything before it is equal, so it is an answer to the same query, and it lies in or before the first frame whose states differ. □
The lemma makes a witness meaningful: once every answer but the renderer’s is fixed, which for two browsers means pinning the Math functions (Section 4), two runs can part only through the renderer’s replies, and the first different reply marks where they begin to part. A split without a logged witness points to an unequal , here a costume measured differently, or to a channel outside Table 1.
The next result explains where witnesses occur. Let A and B be the true shapes of a and b at the query: the points where the vector drawing, transformed to stage coordinates, is painted at all. The model leaves out costumes with text, whose shape depends on the browser’s fonts, and graphic effects that move the sampled point. Let d be the Euclidean distance. Say that R draws a within δ if, at every on-stage point p, (i) implies , (ii) and imply , and (iii) and imply . An exact drawing marks just the texels that the shape reaches, so each marked texel’s centre lies within half a texel diagonal of A. For a point p at fraction u of the costume’s measured width w, the renderer reads texel of an outline texels wide, and with linear sampling also the next one, so every texel it reads for p lies within 2.5 texels of p along each axis if p is in the costume’s box, and for within just outside it. Hence an exact drawing meets (i) and (ii) with texels in its box and, for , more just outside it, and the box of its costume meets (iii); a texel spans stage pixels for a sprite drawn at size z.
Theorem 1
(Near contact). If R and draw a within and b within and , then (1) , and (2) no integer on-stage point of lies farther than from and farther than from .
Proof.
Suppose holds and does not; the other case is symmetric. The first gives an integer point p with and ; by (i), and , so . For (2), suppose an integer on-stage point lies farther than from and than from . By (ii), and , and by (iii) , so holds, a contradiction. □
Corollary 1
(Margin). If, at a test whether a touches b, the two sprites are either more than apart or overlap at some integer on-stage point deeper than inside A and inside B, then every renderer that draws them within these margins gives that test the same answer.
In words, browsers can disagree about a touching test only within about of contact, on either side: at the moment a saw’s tooth reaches a runner. Sprites thinner than , such as a one-pixel line, are never deep enough inside each other to be immune. The distance cannot be observed, but the gap between the sampled outlines of the renderer that answered “not touching” can, and Section 5.3 measures it at every touching witness: one stage pixel, the smallest gap the integer grid allows. Informally the argument covers bounds too: a bounce or edge test can differ only when a sprite is within about of the stage’s edge, as long as its hull comes from its current outline. Colour tests read colours rather than coverage and are outside the model.
Lemma 2
(History). Assume that is a function of , as it is in a fresh page whose 2D canvases do not move between GPU and CPU (Section 5.4). Then at a query is a function of the state and of the scales of the costumes involved, now and when their cached hulls were computed, not of the state alone: two runs in the same state can answer differently if one of them drew a costume larger earlier, for any sprite or clone, or on a canvas with a larger pixel ratio. If every outline is drawn at one fixed scale , is a function of the state.
Proof.
By Definition 1, depends on , a maximum over the run’s past, and generally differs for different k; Figure 3(b) shows the consequence: Chrome’s runner drawn at covers 2 points of the saw that its outline at misses. The state records the sprites’ current sizes but neither their past sizes nor the canvas’s pixel ratio. With a fixed scale, the outline no longer depends on the past, and Definition 2 reads only the state. □
Bounds carry one more piece of history: the renderer caches a sprite’s convex hull and recomputes it only after the costume, the sprite’s visibility or a shape-changing graphic effect changes, so a bounds reply, and the box the touching scan reads, can come from an outline that a larger drawing has since replaced. Section 5.2 shows that a past drawing alone can change a game. The last result says what a fix must cover.
Theorem 2
(Determinism under a fixed outline). Suppose that (a) the outline of every vector costume is , an RGBA image computed by one deterministic rasterizer from the costume’s SVG at a fixed scale ; (b) colour tests are answered on the CPU from the outlines, the bitmaps and the pen layer; (c) two runs share the inputs and device readings, the random and clock streams of Lemma 1, the values of the Math functions, the costumes’ measured boxes, the decoded pixels of bitmap costumes and the pen layer’s pixels; and (d) the program makes only the queries of Table 1. Then the two runs are equal, whichever browser, screen, GPU or computer draws them.
Proof.
By (a), (b) and (d), the reply to every renderer query is a function of the state and of the costumes: touching and bounds read for vector costumes and the decoded pixels for bitmap costumes, colour tests read the colours of the same outlines, the fence and the size limits read the measured boxes, and (c) makes the decoded bitmaps, the measured boxes and the pen layer equal. With (c), every answer in every frame has the same value in both runs, and Lemma 1 gives equal states by induction. □
Theorem 2 turns the list in (c) into a prediction, which Section 5.5 checks: under the fix, a game that still splits must split through a Math function, a device or the clock, a costume measured differently, a bitmap decoded differently or the pen layer.
4. Replaying a Game Under One Change
Lemma 1 says what a fair comparison needs: equal inputs, random numbers, clocks and Math values, with only the renderer allowed to differ. Figure 2 shows how we provide it, in five stages; Algorithm 1 gives the replay and the witness search, and Algorithm 2 the fix.
| Algorithm 1: Replay plays a game in one setting; Witness names the first logged answer at which two runs part. |
|
- Replay The replay, written for this study, is a web page around Scratch’s own packages as published on npm, unmodified: scratch-vm 5.0.300, scratch-render 2.2.84, scratch-storage 6.2.1 and scratch-svg-renderer 3.0.114, with the editor’s fonts from scratch-render-fonts. Playwright 1.63 drives the page in a real browser. Replay loads the project on a 480×360 stage and calls the virtual machine’s own step function once per frame, for 300 frames or ten seconds of play. Before any other script runs, a layer of about ninety lines fixes the inputs that the page would otherwise take from the browser (Line 5). Math.random becomes a seeded generator that restarts at every green flag. The clocks Date and performance.now return a virtual time that is s after t frames, or later if reads have carried it past that time, and advances a fiftieth of a millisecond per read, so that a loop waiting on the clock still ends. Timers fire on this clock between frames, and the network fails at once. The virtual machine gives its scripts at most three quarters of a frame; on this clock that budget is counted in reads, as in [13], so a slow machine and a fast one do the same work per frame. A game’s keys are those its scripts listen for, held from the fifteenth frame (Line 7) as in [13]; 349 of the 500 games listen for keys. No mouse input is sent, so the pointer touches no sprite.
- Perturb Each comparison of Table 2 targets one setting: the browser engine, the screen (the page’s device pixel ratio), the stage (a 960×720 canvas, as a larger stage in the editor), the graphics path (software against the GPU), the canvas path (Chrome 154’s 2D canvases on the GPU against the CPU), the window (headless against windowed) or the computer (one build of Chrome on a Mac and on a Windows workstation); Section 5 lists the browsers. A run plays four games at a time in four pages. Safari and Firefox reuse each page, with its virtual machine and renderer, for game after game; Chromium does so only in Section 5.4, where it does not reproduce its own runs, and otherwise gives each game a fresh page (Line 2). The browser comparison also mixes graphics paths (its Chrome draws in software) and fresh and reused pages; Section 5.1 shows that neither changes which games split. To test the cause of the splits, we also run the browsers with one portable implementation of every transcendental Math function, from the stdlib.js library, installed before the virtual machine loads. The three engines then return the same bits for all 20,000 arguments of our check, as Lemma 1 requires.
- Compare After every frame Replay records the state (Line 8): every variable, and every sprite’s and clone’s position, size, direction, visibility and costume, rounded to whole units, with clones in the order the virtual machine lists them. A game ends differently, or splits, in two settings when its last state differs, which undercounts render-dependent games since positions are rounded.
- Pinpoint Line 4 logs every answer to a query of Table 1. Witness takes the first logged answer that differs, up to the first frame whose states differ (Definition 3), with two refinements. Boxes that differ by a fraction of a pixel are common and usually harmless, so a differing box counts only in the frame where the states first differ (Line 16); and logs that list different queries end the search without a witness (Line 15). We say that a split starts at its witness. In the running example, the Chrome and Safari logs agree on all 258 touching tests of frames 1 to 129. In frame 130 the second touching test, whether the runner touches the saw, answers no in Chrome and yes in Safari, and in the same frame Safari’s runner reacts to the hit. Given another run’s logs, Line 4 also replays a game with that run’s answers, as long as both runs ask the same queries; Section 5.3 uses this to test whether the pixels carry a split.
- Six lessons from the controls A browser run has more inputs than the program’s own. Each of the following broke one of our controls (two batches of a run in different orders, a reused page against a fresh one, one game played after each of the others) or our record of a run. (i) A vector costume is decoded asynchronously, after the project has loaded, so a run that starts at once tests against a costume not yet drawn, at a moment that depends on the machine’s load; we wait until every vector costume has decoded (Line 3). (ii) The editor’s fonts load asynchronously too, and a costume without a view box is measured, text included, when it loads. Before its font arrives, a title that Chrome measures 337.4 units wide measures 272.9, and whether the font has arrived depends on the games played before in the page; we load the fonts before any project (Line 2). (iii) The say and think blocks with a duration wait on the browser’s timer, not on the virtual machine’s clock, so how many frames they last depends on the machine’s speed; we run the page’s timers on the virtual clock. (iv) The text-to-speech and translation blocks call a web service through a queue that the page keeps between games and that reads the clock when it is created. Such a game reads the clock once more in a fresh page than in a reused one, and in the editor the answers arrive whenever the service responds; we set these games aside (Section 5). (v) A large screenshot draws every visible costume at the large scale and, by Lemma 2, can change the outlines of every later frame, and so the game. (vi) Even the record can depend on the engine. In 18 games a sprite holds two variables with the same name, and a sort that leaves the tie unbroken lets Firefox order them differently from Chrome and Safari, so that such a game can appear to split in its first frame; we order variables by name, type and identifier.
- The fix Theorem 2 asks for two changes to the collision outline, and for colour tests that read it (Algorithm 2). Step 1 draws each vector costume’s outline once, at a fixed scale (the costume’s own size, , unless stated otherwise), and keeps the renderer from replacing it with larger drawings (Line 6). Step 2 draws the outline with one portable rasterizer, resvg compiled to WebAssembly [36], which computes the same pixels in every browser; we pass it the editor’s seven fonts, so that text is drawn in them (Line 3). Both steps answer every colour test on the CPU from the outlines (Line 1), as condition (b) of Theorem 2 asks, and draw every texture on the screen as before (Line 5). The patch, about sixty lines of JavaScript, is applied after the project loads. For the ablation we run each step alone, with colour tests on the CPU: Step 1 runs Line 3 with the browser’s own rasterizer instead of resvg, and Step 2 runs it with resvg at the renderer’s own scale, the largest requested so far.
| Algorithm 2: The fixed outline, installed in the renderer once the project has loaded. |
|
5. Evaluation
We ask five questions. RQ1: how often does the browser change how a game ends? RQ2: within one browser, do the screen, the stage, the graphics and canvas paths, the window and the computer matter? RQ3: where do the splits come from? RQ4: does a grader see the game a child plays, grade it the same way, and see the same game twice? RQ5: does a fixed outline remove the splits?
- Games We collected the games through the Scratch website’s public project search for game in English. The 1,200 most popular results and the 600 top trending ones, without repeats, give a pool of 1,756 projects. We removed the 72 we had examined while designing this study and walked a seeded shuffle of the rest, skipping projects that are not Scratch 3 projects (238), exceed 15 MiB (162) or reference a missing asset (1). The first 40 became development games, on which we built and debugged the replay, and the next 500 the evaluation games, frozen before any evaluation run. Lesson (vi) of Section 4, the order of same-named variables, was learnt on these games rather than on the development games. Every game is a public project, shared under CC BY-SA 2.0. We set aside the 21 games that use the camera or a web service, inputs outside the replay’s control. Of the rest, 5 fail in all three browsers, 4 of them by exceeding a four-minute limit per game, and one more exceeds it in Firefox alone. Counting these 27 games as splits or as agreements bounds the browser splits at 6.6%–12.0% of the 500. Every comparison counts the 473 games left, less any that fail in one of its own runs (one in Table 2, for Chrome 154 in software); other bases are stated. Together, the 102 runs of all 500 games, three of them thirty seconds long, replay 16 million frames and log 3.55 billion pixel tests.
- Setup The Mac has an Apple M5 Max and macOS 27, the Windows workstation an NVIDIA RTX 5070 Ti and Windows 11. We compare three browser engines throughout, in the builds that Playwright 1.63 ships and drives headless: “Chrome” is Chromium 153 drawing WebGL in software (SwiftShader), and “Safari” (WebKit 26.6) and “Firefox” (Firefox 155) draw on the GPU. “Chrome 154” is Google Chrome as released, which draws on the GPU (Metal on the Mac, Direct3D 11 on Windows) unless stated, and “Edge 154” is Microsoft Edge on Windows. Chrome 154 runs headless, in software or at a ratio of two as on a child’s laptop; on Windows it runs headless, windowed or in software, and Edge 154 headless or windowed. On the Mac, a windowed run of Chrome 154, stopped early, played 403 of the games, each exactly as the headless run.
5.1. RQ1: Browsers
Across Chrome, Safari and Firefox, 33 of the 473 games (7.0%, about one in fourteen; 95% interval 5.0–9.6%) end in at least two different states after ten seconds (Table 2), and each pair of browsers disagrees on 4.7% to 5.9% of the 473. The rate holds up. With Chrome drawing on the GPU the browsers split the same 33 games, and with a fresh page per game in every browser the same 33. With every key pressed and released at random they split 41 of 468, 24 of them the same. With a second seed, Safari and Firefox split 27 of 472, 23 of them under both seeds. After thirty seconds of play instead of ten, 8.1% of 472 games end differently, against 7.0% at ten seconds in the same runs. Edge 154 and Chrome 154 on Windows, which share Chromium 154’s rasterizer, end all 473 games alike.
The splits are not slow drifts: per pair, the median game’s runs part 1.1 to 1.7 seconds into play, 16 of the 33 within the first second, and 6 more games part and rejoin before the end. The rate follows how much a game tests pixels: of the 301 games that test any pixel in ten seconds, 10.3% split, 11.4% of those that listen for keys and 5.5% of the rest. A split is not yet a grade, and its effect varies: in 26 of the 33 games a sprite ends in another place, in 15 a variable ends with another value, and in 9 a visible sprite ends at least ten units away. In the extreme, a paintball game ends with the orange team at 140 points in Chrome, 136 in Safari, 139 in Firefox and 138 in Chrome 154 on Windows.
- In release browsers and in the editor Driven through WebDriver, release Firefox 157, set to UTC as our replay is, plays all 473 games exactly as Playwright’s Firefox 155, frame for frame. Release Safari 27, in its own window on the Mac’s screen, plays 472 of 473 exactly as WebKit at that ratio; the other game writes a date three years ahead, which Safari 27 gives in the Mac’s time zone. The Scratch editor itself splits 22 of the 33. We loaded 73 games, the 33 that the browsers split in Table 2 and 40 that they do not, into the editor in release Chrome 154 and Firefox 157, replaced its clock and random numbers as in Section 4, and stepped its own virtual machine with the replay’s frame loop, its interface detached. In each of the two browsers, the Scratch editor plays 67 of the 73 games exactly as our replay does, frame for frame. The others differ outside the renderer: in 2 through a variable that the block workspace adds to a project file that lacks it, and in 4 through a sound that the editor waits for and our replay, which has no audio, does not. In the editor, Chrome 154 and Firefox 157 end 22 games differently, all of them games they split in our page too and none of the other 40; the one game that only our page splits waits for a sound. Safari 27’s editor, drawing its stage at 1020×765, matches WebKit at that size in every frame for 59 of the 73 games. Of the others, 6 differ through the workspace’s variable or a sound, as in Chrome 154 and Firefox 157, one through the date, and 7 in the editor’s page only, since release Safari plays them as WebKit does in ours.

5.2. RQ2: One Browser, Different Settings
A browser does not agree with itself either. On a screen with a pixel ratio of two, Safari ends 7.0% of the games differently and Chrome 7.0%, and a 960×720 stage changes 7.0%. That is more games than any one change of browser and as many as the three browsers together, though not the same games: 50 games (10.6%) split across the browsers or in at least one of these settings. Lemma 2 predicts the effect: a sharper screen or a larger canvas doubles the scale requested to draw the stage, and the outline follows the largest drawing (Figure 3(b), right). Two of its consequences can be tested alone. The screen and the larger stage make the same drawing requests, and they end all 473 games alike. To isolate the past, we prime a run by drawing every vector costume once at before the green flag, so that the state, the screen and every later drawing are those of the run and only the past differs. Chrome then ends 7.9% of 471 games differently and Safari 8.7% of 472: one drawing that never reaches the screen changes the game.
The graphics and canvas paths, the window and the computer matter less. The GPU changes 0.6% of the games, Chrome 154’s canvas path 3.0%, a window at the same pixel ratio none, and the same Chrome 154 build changes 2.5% on a Windows workstation instead of the Mac, or 1.3% when both draw in software.

Figure 3.
The pixels behind the running example. (a) The runner’s outline as Chrome and Safari draw it: 53 of its 2,254 texels, all on its edges, are covered in one browser only (orange). (b) Of the 686 stage points in the box the touching test scans, the part that holds the contact (grey: runner only, blue: saw only, orange: both, pale: neither). No point is covered by both of Chrome’s outlines, and 3 by both of Safari’s: its outline of the runner reaches one row of stage points higher at the hand, into the saw’s tooth, and its outline of the saw covers one more point. Chrome on a screen draws the runner at (99×92 texels instead of 49×46), its outlines share 2 points, and it plays every frame as Safari does.
Figure 3.
The pixels behind the running example. (a) The runner’s outline as Chrome and Safari draw it: 53 of its 2,254 texels, all on its edges, are covered in one browser only (orange). (b) Of the 686 stage points in the box the touching test scans, the part that holds the contact (grey: runner only, blue: saw only, orange: both, pale: neither). No point is covered by both of Chrome’s outlines, and 3 by both of Safari’s: its outline of the runner reaches one row of stage points higher at the hand, into the saw’s tooth, and its outline of the saw covers one more point. Chrome on a screen draws the runner at (99×92 texels instead of 49×46), its outlines share 2 points, and it plays every frame as Safari does.

5.3. RQ3: Where Splits Come From
For each of the 33 games that end differently across the browsers, we looked for the witness of the pair that parts earliest. In 67% of them (22) the witness is a pixel test: a touching test between two sprites in 10, a colour test in 8, and a bounds query of bouncing or edge detection in 4. The witness is close to the damage: in all 22 games it lies in the frame where the states first differ or the one before. The other 11 games have no pixel witness: in 9 the two logs list different queries first, in one a costume’s measured size differs, and in one no logged answer differs before the states do; pinning the arithmetic, below, removes 5 of them.
These witnesses are tentative, since the browsers’ engines also differ in their arithmetic. They return a different last bit of Math.atan for 2.8–4.5% of 20,000 arguments and of Math.sin and Math.cos for 3.2–4.4%, and Scratch rounds the results of its sine and cosine blocks, but not its inverse tangent or the sines and cosines inside a move. With one portable Math in all three browsers, as Lemma 1 requires, the browsers split 28 of 472 games (5.9%). Of these splits, 86% start at a pixel test (10 touching, 9 colour and 5 bounds tests). Another two start at a bounds query if differing boxes count in every frame: in each, a box differs before any state does. The last two start at a costume that the browsers set up differently: a text costume that Firefox measures to another size, and a costume half a unit thick that Safari never decodes (it leaves 5 costumes under a unit thick undecoded, in 4 games; Chrome and Firefox decode them). Without a renderer, where no pixel is tested, the pinned browsers split none of 471 games, and with their own Math they split 5, each through the arithmetic.
Lemma 1 says where two runs first part, not that the witness alone parts them, so we changed the answers, replaying in Chrome with pinned Math each of the 24 games with a pixel witness between Chrome and another browser. Replacing only the witness answer by the other browser’s changes the ending in 12 of them and gives the other browser’s ending in 5, the running example among them; in the rest the renderers keep disagreeing at later tests, mostly as the same contact is tested again. In the running example, Chrome given Safari’s one answer counts the touch a frame sooner, and the later saw passes over its runner: Chrome ends with 5 points, as Safari does. Replacing every logged renderer answer makes Chrome end exactly as the other browser in all 24 games, and Chrome fed its own answers reproduces itself in all of them. These splits are the pixels’ doing. In 23 of the 24 pixel-witnessed games the two browsers also measure every costume to the same box, the equal start that Lemma 1 assumes; in the other a box differs by less than a millionth of its size.
Figure 3 shows the pixels behind the running example’s witness. The two outlines of the runner differ along its edges, and Safari’s reaches one row of stage points higher at the hand, into the saw’s tooth. On a screen Chrome draws the runner at , its outlines share points too, and it plays every frame as Safari does. Theorem 1 predicts that every touching witness looks like this. At each of the 10 touching witnesses of the pinned comparison, we replayed the run that answered “not touching” and measured the gap between the two sprites’ outlines over the boxes the test scans for them, sampled as the test samples them. The gap is one stage pixel in every one of them, the smallest gap the integer grid allows; counted in texels of the coarser outline, the largest is 1.31. Conditions (i) and (ii) hold for most outlines at . A sixty-game sample has 1,584 vector costumes without text or clip path that resvg draws; taking resvg’s drawing at as the true shape, each browser draws 97.2–99.8% of them to within one texel: no texel it marks, or leaves unmarked inside the shape, is farther off. With the sampling of Section 3, is then texels in the costume’s box, four along each axis, and for at most more just outside it. We leave out the 125 costumes with a clip path, which every browser draws more than a texel away from resvg’s drawing. Most of the 3 to 44 exceptions per browser lie two texels off or hold an embedded bitmap. Any two browsers rasterize at least 84% of the sample’s 2,619 vector costumes differently, and none of its 1,455 bitmap costumes. Sizes agree but for text: even with the editor’s fonts loaded, 33 of the 909 vector costumes with text, in 4 of the sixty games, are measured to a different size, and no other costume differs by more than a millionth.
Two controls close the argument. With the arithmetic pinned, none of the 123 games without a block that asks the renderer about pixels splits. And Table 1 is complete for the games we compare: a census of the 28 public renderer methods called during play in 494 games, including the 473, finds that the other methods returning a value read no pixels or never reach the state. They create clones, speech bubbles and the pen layer, set the layer order, report sizes, convert the mouse position or place a bubble.

5.4. RQ4: Graders
A grader on a server often runs a headless browser without a GPU, and a child a browser on a laptop. Headless Chrome drawing in software, our grader, does not always see the game a child sees. It disagrees with Safari on 5.9% of the games, with Firefox on 4.7% and with the same Chrome on a screen on 7.0% (Table 2). A child’s laptop changes several settings at once: the grader disagrees with Safari at a pixel ratio of two on 9.1% of the games, with Chrome 154 drawing on the GPU at that ratio on 7.0%, and with Chrome 154 in a window on a Windows computer on 3.0%.
Verdicts change less often than end states, because a check reads a few quantities at a few moments. We wrote checks for two Raspberry Pi Foundation tutorials that end in a game, Boat Race [29] (13 checks) and Catch the Dots [30] (11), from the steps that each tutorial asks a learner to follow; 7 checks in each depend on a touching test. Each check sets up one situation, plays it, and passes, fails, or stays untested when the remix never reaches what it checks. We graded seeded samples of 400 and 1,000 of the 31,634 and 10,174 public remixes of the two starter projects that pass the games’ filter (Table 3). Between Chrome and Safari, a verdict changes for 2.3% of the Boat Race remixes that run the checks and 1.9% of the Catch the Dots remixes. All 9 Boat Race checks that change turn from pass to fail or back; of the 25 Catch the Dots checks that change, 17 do, and the others turn between a verdict and untested. The screen matters about as much as the browser, and in Catch the Dots more: a sharper screen changes the verdict of 3.9% of the remixes in Chrome and 4.6% in Safari, and the grader and the laptop disagree on 4.1%. In Boat Race, Safari’s screen and the laptop change 1.8% and 1.5%. In a second grading, Chrome changes no verdict in either tutorial (in Catch the Dots on 300 of its remixes), and Safari changes the verdict of one Catch the Dots remix (Table 3). Far more checks keep their verdict though the run differs: in 482 Catch the Dots checks the recorded reason differs between Chrome and Safari but the verdict does not, typically because a dot lands, the score changes or the game ends at a slightly different moment or place.
Whether the grader sees the same game twice depends on how it runs its browser. Two batches in different orders end every game alike in Safari (at both pixel ratios) and Firefox, which reuse each page, and in Chromium with a fresh page per game. A Chromium page that plays game after game does not: in two orders, 8 games end differently in software, 9 on the GPU and 3 in Chrome 154 (7 on Windows), 16 of these 20 at a pixel test. One carrier is the browser’s store of decoded images, shared by every page of a process: a costume that embeds a bitmap, as the running example’s runner does, is drawn from a copy that earlier pages decoded, and its outline can change with them. Giving each game’s images their own addresses removes 3 of the 8 software splits, not the runner’s, and adds 1, so it is not the only carrier; Chrome 154’s two canvas paths (3.0% of the games when one is forced) are another candidate. A grader avoids these splits by giving each game a fresh page, as our replay does in Chromium.

5.5. RQ5: A Fixed Outline
Table 4 repeats the comparisons with the fix. As Column 2 shows, Step 1, one outline per costume at a fixed scale, removes the splits of a sharper screen and a larger stage, as Lemma 2 predicts, but not the browsers’; Safari’s screen still splits 2 games, only in reused pages. With their own rasterizers, 8.9% of the games still split, more than without the fix, and 0.4% between Chrome’s software and GPU paths. A finer outline does not remove them: at , 2 and 4, Safari and Firefox split 38, 30 and 37 games under Step 1, against 25 without the fix. Every fixed run also answers colour tests on the CPU, a change we have not isolated. Column 3 shows the converse: Step 2 alone, one rasterizer at the renderer’s own scale, cuts the browsers’ splits to 1.5% but leaves the screen’s at 6.8% in Safari. With both steps (Column 4), the browsers split 6 of the 470 games (1.3%, from 31, or 6.6%), and of the other settings on one computer only Chrome 154’s canvas path splits a game, the paintball game of Section 5.1. Our prototype loses 3 games: two split games, one to a costume 24,000 units wide whose outline cannot be allocated and one to an outline that rounds to zero texels, and a game that takes 220 s in Firefox without the fix and over four minutes with it. A deployed fix would cap the outline’s size and skip empty outlines.
Theorem 2 predicts where the remaining games split. With both steps and one portable Math, the browsers split 2 games, each through a channel that condition (c) lists: a paint trail on the pen layer, which the three browsers draw differently and a colour test reads, and a costume’s text, which Firefox measures to another size. Without pinning, the other 4 split through the arithmetic: they and the game lost to the 24,000-unit costume are the 5 that split without a renderer. The same Chrome 154, fixed, splits only the paintball game between the Mac and Windows (1 of 471) and between its two canvas paths, each time through a colour test that reads the pen layer. Across all pairs of a fixed run on Windows and one on the Mac, at most 5 games split.
Is the fix free? It changes the drawing that decides touching, and so some outcomes: under both steps, 5.3–5.7% of the games end differently than in Chrome, Safari or Firefox without it, about as many as a change of browser does. The change happens once: after it every setting we tested agrees, up to the channels above. We fix , the scale at which the renderer draws most sprites on a screen, so that the one-time change stays small. A finer scale keeps the agreement, with 7 browser splits at and 7 at , but changes more games once: 8.3–9.1% and 10.0–10.9%. In Safari and Chrome, the fix adds a median of 72–89 ms to loading a game of the sixty-game sample and no measurable time per frame. In the running example, the fixed Chrome too answers “touching” at 4.33 s, and every browser ends with 5 points. Of the 19 Catch the Dots remixes whose verdict changes between Chrome and Safari, none changes under the fix, nor does any of 100 others drawn at random; one remix still changes between Firefox and the other two. In Boat Race no remix changes between fixed browsers (Table 3).

6. Discussion
- For graders, test tools and competitions A grader grades the game its own browser draws, and a game that ends differently is a grade that can change. Our measurements suggest four steps. (i) Pin the screen and the stage: grade at a device pixel ratio of one on a 480×360 canvas, never draw the stage larger during a graded run, and take screenshots from a separate replay. This costs nothing and removes two effects, each larger than a change of browser. (ii) Play one game per page and load the editor’s fonts first; otherwise Chromium’s drawing and a web-service block’s clock reads depend on the games graded before, and a text costume’s size on when its font arrives (Section 4 and Section 5.4). (iii) State the browser and the computer next to the seed, since even after (i) and (ii) they change 1.3% to 7.0% of the games. (iv) Where a verdict matters, grade under the fixed outline, which gave the same verdict in every browser to all but one of the remixes that all three graded to the end; a child whose editor does not use it may still see a different game. Grading twice, in two browsers or with and without the fix, also finds the verdicts that the renderer decides. A competition that ranks by score can state the browser, the computer, the pixel ratio and the stage size, or judge under the fixed outline, so that a participant can reproduce the score that ranked them.
- For Scratch The fix buys consistency, not correctness: its outline is one well-defined drawing among many, no truer than any browser’s, and it makes touching a function of the state alone. Its price is a one-time change of behaviour in 5.3–5.7% of the games, which a version flag in the project file would spare existing projects. Step 1 adds nothing to the editor’s download and makes Chrome agree with itself on a screen and a larger stage, and Safari on a screen but for 2 games in reused pages. Step 2 adds a rasterizer, the 2.5 MB WebAssembly module that resvg-js publishes (0.9 MB with gzip), and reuses the fonts that the editor already ships. Neither step fixes text measurement: the title of lesson (ii) is 341.4 units wide in Firefox and 337.4 in Chrome, and a deployed fix would measure text with the portable rasterizer too. Nor does the fix decode a costume that a browser leaves undecoded.
- For children and teachers A costume imported as a bitmap has one outline in every browser we tested: none of the 1,455 bitmap costumes of our sample is rasterized differently. For vector costumes, Corollary 1 gives a rule of thumb. A game that asks whether two sprites touch when they are clearly apart or clearly overlapping gets the same answer everywhere; a game that asks at the moment they meet, as the runner game does, lets the browser decide. A loop that asks touching? every frame often asks at that moment, so the rule helps most in games that check for a collision after a move of several pixels.
- Looking changes the game Lesson (v) of Section 4 reaches beyond our replay: any tool that draws the stage larger than the game does, for a screenshot or a zoomed view, can change the outlines of every later frame (Lemma 2). Switching the editor to full screen and back should thus give a finer outline to each vector costume drawn larger than before; we have not measured this in the editor.
7. Threats to Validity
- Internal validity Our conclusions rest on the replay holding everything fixed but the drawing and, unless we pin it, the engines’ Math. Four controls check it (Section 5.3 and Section 5.4): batches in different orders end every game alike in the pages our runs use; with the arithmetic pinned, no game splits that never asks the renderer about pixels, and none splits without a renderer; and Chrome fed its own logged answers reproduces itself in every witness game. The replay departs from the editor in ways that affect every browser alike: it counts the frame’s work budget in clock reads rather than milliseconds, waits for costumes and fonts, runs timers on the virtual clock, ends every sound at once, has no network, and never clicks or drags, so the query behind clicking and dragging is untested. The editor itself reproduces the replay frame for frame in most of the games we played there; the others differ through a workspace variable, a sound, the date or the editor’s page (Section 5.1). The fix’s agreement is shown under the replay, as a patch to one version of the renderer, not in the unmodified editor.
- External validity Our games, popular public projects from Scratch’s search for game, may differ from typical projects and from classroom work; the grader experiment adds tutorial checks on public remixes, closer to classroom work. Each game ran for ten seconds with its keys held and the mouse still; random key presses, a second seed and thirty seconds of play give similar rates (Section 5.1), but a player exercises more paths. We measured two versions of each browser engine, one version of the renderer in our page, and one Mac and one Windows computer; Linux, Chromebooks, pixel ratios such as 1.25 or 1.5 and older browsers may differ more. A child’s editor keeps one page open for hours, which we measured only through pages reused for game after game (Section 5.4).
- Construct validity A game ends differently when any recorded part of its state after ten seconds differs, including a hidden variable or a clone, and an end state is not a grade. We therefore also report how far visible sprites move and measure verdicts directly with tutorial checks. We wrote these checks ourselves from the tutorials’ steps; a teacher’s or a competition’s checks, which test other things at other moments, may change more or less often.
8. Related Work
- Testing and grading Scratch programs Test generators and frameworks [7,11,15,35], debuggers [8], static analyses [4,14,24], graders [17] and hint generators [26] examine a Scratch program’s code or its runs. The dynamic ones read positions, scores and collisions from a run, and so rely on the run being a function of the program and its inputs. Other hidden inputs of a Scratch run are the order of the sprites’ layers [12] and the redraw requests of visible sprites, which decide how much of a frame the scripts get [13]; the renderer, unlike these, acts through the pixels it draws.
- Flaky tests A flaky test passes and fails on the same code [10,20,28]. NonDex finds code that assumes more than an API specifies [16]; a game that asks whether two sprites touch at the moment they meet assumes more than the renderer promises. Render splits differ in one respect that matters for detection: a rerun in the same browser rarely reveals them. In our reruns without the fix, games ended differently only in Chromium pages that play game after game, and one verdict changed, in Safari (Section 5.4).
- Cross-browser differences and fingerprints Testing tools compare a page across browsers to find differences in behaviour and layout [6,22]. The differences we study go unseen on the screen and matter only because a program reads them back. Canvas fingerprinting reads them back on purpose, to identify a machine [1,18,25]; a Scratch game reads them by accident, and they decide how it ends.
- Arithmetic and graphics Floating-point results can depend on more than the source code [23]; the engines’ Math functions alone split 5 of our games. A rendered image is under-specified, so shader compilers are tested by comparing the images of equivalent shaders rather than against one reference image [9]; we look at the same under-specification from a program whose control flow reads the image.
- Replay and determinism Record/replay tools for the web capture a page’s inputs [2,5], and deterministic multithreading makes a program’s output a function of its input [3,19,27]. Our replay carries the first idea across browsers, and our fix carries the second into the renderer (Theorem 2). Unlike a recorder, our replay cannot tell what a particular child saw; it tells what each renderer would have shown for the same inputs.
9. Conclusion
Whether two Scratch sprites touch is decided by pixels, and these pixels depend on the browser, the screen and the computer: across Chrome, Safari and Firefox, 33 of the 473 popular games end differently after ten seconds, and the editor in release Chrome and Firefox splits 22 of the 33. With the arithmetic pinned, 86% of the browser splits start at a pixel test, and Chrome, fed Safari’s or Firefox’s renderer answers, ends as that browser in all 24 games we tested. Because the renderer keeps the largest drawing of each costume, a sharper screen or a larger stage changes more games within one browser than any pair of browsers, and one drawing that never reaches the screen can change a game. In Chromium, so can the games a page played before. The splits reach grades, though less often than end states: two tutorials’ checks change their verdict between Chrome and Safari for 2.3% and 1.9% of the sampled remixes that run them. One outline per costume, drawn at a fixed scale by one rasterizer, makes every setting we tested agree on all but a handful of games, which split through the arithmetic, a paint trail or a costume’s text. We hope that graders will state the browser, the screen and the computer they grade with as they state a seed, and that Scratch will one day make touching independent of all three, as Theorem 2 shows it can be.
References
- Gunes Acar, Christian Eubank, Steven Englehardt, Marc Juarez, Arvind Narayanan, and Claudia Diaz. 2014. The Web Never Forgets: Persistent Tracking Mechanisms in the Wild. In Proceedings of the 2014 ACM SIGSAC Conference on Computer and Communications Security (CCS). 674–689. [CrossRef]
- Silviu Andrica and George Candea. 2011. WaRR: A Tool for High-Fidelity Web Application Record and Replay. In Proceedings of the 41st IEEE/IFIP International Conference on Dependable Systems and Networks (DSN). 403–410. [CrossRef]
- Tom Bergan, Owen Anderson, Joseph Devietti, Luis Ceze, and Dan Grossman. 2010. CoreDet: A Compiler and Runtime System for Deterministic Multithreaded Execution. In Proceedings of the Fifteenth International Conference on Architectural Support for Programming Languages and Operating Systems. 53–64. [CrossRef]
- Bryce Boe, Charlotte Hill, Michelle Len, Greg Dreschler, Phillip Conrad, and Diana Franklin. 2013. Hairball: Lint-inspired Static Analysis of Scratch Projects. In Proceedings of the 44th ACM Technical Symposium on Computer Science Education (SIGCSE). 215–220. [CrossRef]
- Brian Burg, Richard Bailey, Amy J. Ko, and Michael D. Ernst. 2013. Interactive Record/Replay for Web Application Debugging. In Proceedings of the 26th Annual ACM Symposium on User Interface Software and Technology (UIST). 473–484. [CrossRef]
- Shauvik Roy Choudhary, Mukul R. Prasad, and Alessandro Orso. 2013. X-PERT: Accurate Identification of Cross-Browser Issues in Web Applications. In Proceedings of the 35th International Conference on Software Engineering (ICSE). 702–711. [CrossRef]
- Adina Deiner, Patric Feldmeier, Gordon Fraser, Sebastian Schweikl, and Wengran Wang. 2023. Automated Test Generation for Scratch Programs. Empirical Software Engineering 28, 3, Article 79 (May 2023), 63 pages. [CrossRef]
- Adina Deiner and Gordon Fraser. 2024. NuzzleBug: Debugging Block-Based Programs in Scratch. In IEEE/ACM International Conference on Software Engineering (ICSE). ACM, Article 22, 13 pages. [CrossRef]
- Alastair F. Donaldson, Hugues Evrard, Andrei Lascu, and Paul Thomson. 2017. Automated Testing of Graphics Shader Compilers. Proceedings of the ACM on Programming Languages 1, OOPSLA, Article 93 (Oct. 2017), 29 pages. [CrossRef]
- Moritz Eck, Fabio Palomba, Marco Castelluccio, and Alberto Bacchelli. 2019. Understanding Flaky Tests: The Developer’s Perspective. In Proceedings of the 27th ACM Joint Meeting on European Software Engineering Conference and Symposium on the Foundations of Software Engineering (ESEC/FSE). 830–840. [CrossRef]
- Patric Feldmeier, Gordon Fraser, Ute Heuer, Florian Obermüller, and Siegfried Steckenbiller. 2024. A Block-Based Testing Framework for Scratch. In Proceedings of the 24th Koli Calling International Conference on Computing Education Research. Article 1, 12 pages. [CrossRef]
- Xinyue Feng, Hanyuan Shi, and Yuan Si. 2026. The Invisible Scheduler: Dragging a Sprite Can Change What a Scratch Program Does. arXiv:2609.36147 [cs.SE]. [CrossRef]
- Xinyue Feng, Hanyuan Shi, and Yuan Si. 2026. The Invisible Throttle: Running on Borrowed Time in Scratch. arXiv:2609.36152 [cs.SE]. [CrossRef]
- Gordon Fraser, Ute Heuer, Nina Körber, Florian Obermüller, and Ewald Wasmeier. 2021. LitterBox: A Linter for Scratch Programs. In Proceedings of the 43rd IEEE/ACM International Conference on Software Engineering: Software Engineering Education and Training (ICSE-SEET). 183–188. [CrossRef]
- Katharina Götz, Patric Feldmeier, and Gordon Fraser. 2022. Model-based Testing of Scratch Programs. In IEEE Conference on Software Testing, Verification and Validation (ICST). IEEE, 411–421. [CrossRef]
- Alex Gyori, Ben Lambeth, August Shi, Owolabi Legunsen, and Darko Marinov. 2016. NonDex: A Tool for Detecting and Debugging Wrong Assumptions on Java API Specifications. In ACM SIGSOFT International Symposium on Foundations of Software Engineering (FSE), Tool Demonstrations. ACM, 993–997. [CrossRef]
- David E. Johnson. 2016. ITCH: Individual Testing of Computer Homework for Scratch Assignments. In ACM Technical Symposium on Computing Science Education (SIGCSE). ACM, 223–227. [CrossRef]
- Pierre Laperdrix, Nataliia Bielova, Benoit Baudry, and Gildas Avoine. 2020. Browser Fingerprinting: A Survey. ACM Transactions on the Web 14, 2, Article 8 (April 2020), 33 pages. [CrossRef]
- Tongping Liu, Charlie Curtsinger, and Emery D. Berger. 2011. Dthreads: Efficient Deterministic Multithreading. In Proceedings of the Twenty-Third ACM Symposium on Operating Systems Principles. 327–336. [CrossRef]
- Qingzhou Luo, Farah Hariri, Lamyaa Eloussi, and Darko Marinov. 2014. An Empirical Analysis of Flaky Tests. In Proceedings of the 22nd ACM SIGSOFT International Symposium on Foundations of Software Engineering (FSE). 643–653. [CrossRef]
- John Maloney, Mitchel Resnick, Natalie Rusk, Brian Silverman, and Evelyn Eastmond. 2010. The Scratch Programming Language and Environment. ACM Transactions on Computing Education 10, 4, Article 16 (Nov. 2010), 15 pages. [CrossRef]
- Ali Mesbah and Mukul R. Prasad. 2011. Automated Cross-Browser Compatibility Testing. In Proceedings of the 33rd International Conference on Software Engineering (ICSE). 561–570. [CrossRef]
- David Monniaux. 2008. The Pitfalls of Verifying Floating-Point Computations. ACM Transactions on Programming Languages and Systems 30, 3, Article 12 (May 2008), 41 pages. [CrossRef]
- Jesús Moreno-León and Gregorio Robles. 2015. Dr. Scratch: A Web Tool to Automatically Evaluate Scratch Projects. In Proceedings of the Workshop in Primary and Secondary Computing Education (WiPSCE). 132–133. [CrossRef]
- Keaton Mowery and Hovav Shacham. 2012. Pixel Perfect: Fingerprinting Canvas in HTML5. In Proceedings of the Web 2.0 Security and Privacy Workshop (W2SP). https://hovav.net/ucsd/dist/canvas.pdf.
- Florian Obermüller, Ute Heuer, and Gordon Fraser. 2021. Guiding Next-Step Hint Generation Using Automated Tests. In Innovation and Technology in Computer Science Education (ITiCSE). ACM, 220–226. [CrossRef]
- Marek Olszewski, Jason Ansel, and Saman Amarasinghe. 2009. Kendo: Efficient Deterministic Multithreading in Software. In Proceedings of the 14th International Conference on Architectural Support for Programming Languages and Operating Systems. 97–108. [CrossRef]
- Owain Parry, Gregory M. Kapfhammer, Michael Hilton, and Phil McMinn. 2021. A Survey of Flaky Tests. ACM Transactions on Software Engineering and Methodology 31, 1, Article 17 (Oct. 2021), 74 pages. [CrossRef]
- Raspberry Pi Foundation. 2018. Boat race. https://projects.raspberrypi.org/en/projects/boat-race. Starter project https://scratch.mit.edu/projects/247460517/; steps in https://github.com/raspberrypilearning/boat-race.
- Raspberry Pi Foundation. 2019. Catch the dots. https://projects.raspberrypi.org/en/projects/catch-the-dots. Starter project https://scratch.mit.edu/projects/278827421/, now titled “Catch the fruit”; steps in https://github.com/raspberrypilearning/catch-the-dots.
- Mitchel Resnick, John Maloney, Andrés Monroy-Hernández, Natalie Rusk, Evelyn Eastmond, Karen Brennan, Amon Millner, Eric Rosenbaum, Jay Silver, Brian Silverman, and Yasmin Kafai. 2009. Scratch: Programming for All. Commun. ACM 52, 11 (2009), 60–67. [CrossRef]
- Scratch Foundation. 2024. Scratch Statistics. https://scratch.mit.edu/statistics/. Data generated 2024-07-14.
- Scratch Foundation. 2025. scratch-vm: Virtual Machine used to represent, run, and maintain the state of programs for Scratch 3.0. https://github.com/scratchfoundation/scratch-vm. npm package scratch-vm 5.0.300.
- Scratch Foundation. 2026. scratch-render: WebGL-based Rendering Engine for Scratch 3.0. https://github.com/scratchfoundation/scratch-render. npm package scratch-render 2.2.84.
- Andreas Stahlbauer, Marvin Kreis, and Gordon Fraser. 2019. Testing Scratch Programs Automatically. In Proceedings of the 27th ACM Joint Meeting on European Software Engineering Conference and Symposium on the Foundations of Software Engineering (ESEC/FSE). 165–175. [CrossRef]
- The resvg authors. 2024. resvg: An SVG Rendering Library. https://github.com/linebender/resvg. WebAssembly build @resvg/resvg-wasm 2.6.2 of the resvg-js project, https://github.com/thx/resvg-js.
Figure 1.
One public runner game, the same key, seed and clock, drawn by Chrome and by Safari. Holding space keeps the runner hovering, its gravity flipping. The runner scores a point every second; a saw that touches it resets the score. In frame 130 (4.30–4.33 s) a saw’s tooth reaches the runner’s hand; the dashed box is the region the touching test scans. Safari counts the touch at once; Chrome counts it one frame later. The two runners restart one frame apart, and at 9.60 s a later saw hits Chrome’s runner and passes over Safari’s. After ten seconds the game has two endings in the settings we test (below). Stage images: “ver.1.2 Minecraft Run!” by ofuzake_company, Scratch project 731373269, CC BY-SA 2.0.
Figure 1.
One public runner game, the same key, seed and clock, drawn by Chrome and by Safari. Holding space keeps the runner hovering, its gravity flipping. The runner scores a point every second; a saw that touches it resets the score. In frame 130 (4.30–4.33 s) a saw’s tooth reaches the runner’s hand; the dashed box is the region the touching test scans. Safari counts the touch at once; Chrome counts it one frame later. The two runners restart one frame apart, and at 9.60 s a later saw hits Chrome’s runner and passes over Safari’s. After ten seconds the game has two endings in the settings we test (below). Stage images: “ver.1.2 Minecraft Run!” by ofuzake_company, Scratch project 731373269, CC BY-SA 2.0.

Figure 2.
Overview of the method. The editor’s own virtual machine and renderer replay a public game with its keys, random numbers and clock fixed (Stage 1), in two settings, such as two browsers or two screens (Stage 2). The runs are compared after every frame (Stage 3); Algorithm 1 names the first logged answer at which they part, and replaying one run with the other’s logged answers checks that the pixels carry the split (Stage 4). The fix of Algorithm 2 replaces the collision outline, and the comparisons of Table 4 are run again with it (Stage 5).
Figure 2.
Overview of the method. The editor’s own virtual machine and renderer replay a public game with its keys, random numbers and clock fixed (Stage 1), in two settings, such as two browsers or two screens (Stage 2). The runs are compared after every frame (Stage 3); Algorithm 1 names the first logged answer at which they part, and replaying one run with the other’s logged answers checks that the pixels carry the split (Stage 4). The fix of Algorithm 2 replaces the collision outline, and the comparisons of Table 4 are run again with it (Stage 5).

Table 1.
The renderer queries whose replies can reach a run’s state, and what each reply is computed from. The other calls from scratch-vm to the renderer only draw, read no pixels, or return values that never reach the state (Section 5.3).
Table 1.
The renderer queries whose replies can reach a run’s state, and what each reply is computed from. The other calls from scratch-vm to the renderer only draw, read no pixels, or return values that never reach the state (Section 5.3).
| Query (blocks) | Reply is computed from |
|---|---|
| touching sprite? | the outlines of both sprites’ costumes |
| touching mouse-pointer? | the sprite’s outline at the pointer |
| touching colour?, colour is touching colour? | outline and pen-layer colours on the CPU; drawn textures and the pen layer on the GPU |
| bounds (if on edge, bounce, touching edge?) | the convex hull of the outline, cached until the costume, its visibility or a shape-changing effect changes |
| fence (every move) | the costume’s measured box |
| size limits (size blocks) | the same box |
Table 2.
Games (of 473; 472 for Chrome 154 in software) that end differently when one setting changes, with 95% Wilson intervals. The browsers split as many games as a sharper screen or a larger stage; the graphics and canvas paths and the computer split fewer, and a window none.
Table 2.
Games (of 473; 472 for Chrome 154 in software) that end differently when one setting changes, with 95% Wilson intervals. The browsers split as many games as a sharper screen or a larger stage; the graphics and canvas paths and the computer split fewer, and a window none.
| Setting changed | Games | % (95% CI) |
|---|---|---|
| Browser engine | ||
| Chrome – Safari | 28 | 5.9 (4.1–8.4) |
| Safari – Firefox | 25 | 5.3 (3.6–7.7) |
| Chrome – Firefox | 22 | 4.7 (3.1–6.9) |
| at least one pair | 33 | 7.0 (5.0–9.6) |
| Screen, to | ||
| Safari | 33 | 7.0 (5.0–9.6) |
| Chrome | 33 | 7.0 (5.0–9.6) |
| Stage, 480×360 to 960×720 | ||
| Chrome | 33 | 7.0 (5.0–9.6) |
| Graphics path, software to GPU | ||
| Chrome | 3 | 0.6 (0.2–1.8) |
| Canvas path, GPU to CPU | ||
| Chrome 154 | 14 | 3.0 (1.8–4.9) |
| Computer, Mac to Windows | ||
| Chrome 154 on the GPU | 12 | 2.5 (1.5–4.4) |
| Chrome 154 in software | 6 | 1.3 (0.6–2.7) |
| Window, headless to windowed | ||
| Chrome 154 on Windows | 0 | 0.0 (0.0–0.8) |
Table 3.
Tutorial remixes whose verdicts change between two settings, in seeded samples of 400 Boat Race and 1,000 Catch the Dots remixes: those that run a check and finish grading in the settings compared (Runs), those with a check whose verdict (pass, fail, untested) changes (Changed), and the changed checks (Checks). Grader: Chrome in software; laptop: Chrome 154 on the Mac’s GPU at a ratio of two. Chrome graded 300 Catch the Dots remixes twice; the fix regraded the remixes that change between two browsers and 100 others. Dash: not run.
Table 3.
Tutorial remixes whose verdicts change between two settings, in seeded samples of 400 Boat Race and 1,000 Catch the Dots remixes: those that run a check and finish grading in the settings compared (Runs), those with a check whose verdict (pass, fail, untested) changes (Changed), and the changed checks (Checks). Grader: Chrome in software; laptop: Chrome 154 on the Mac’s GPU at a ratio of two. Chrome graded 300 Catch the Dots remixes twice; the fix regraded the remixes that change between two browsers and 100 others. Dash: not run.
| Boat Race | Catch the Dots | |||||
|---|---|---|---|---|---|---|
| Compared | Runs | Changed | Checks | Runs | Changed | Checks |
| Chrome – Safari | 395 | 9 | 9 | 986 | 19 | 25 |
| Chrome – Firefox | 375 | 7 | 7 | 985 | 29 | 38 |
| Safari – Firefox | 375 | 6 | 6 | 985 | 33 | 45 |
| Chrome, screen | – | – | – | 985 | 38 | 56 |
| Safari, screen | 396 | 7 | 7 | 986 | 45 | 71 |
| Grader – laptop | 395 | 6 | 6 | 986 | 40 | 58 |
| Chrome twice | 395 | 0 | 0 | 293 | 0 | 0 |
| Safari twice | 396 | 0 | 0 | 986 | 1 | 1 |
| Fix, any two browsers | 105 | 0 | 0 | 140 | 1 | 4 |
Table 4.
Games that end differently, in % of the games that finish in the cell’s runs: in Column 1, 473 (472 with Math pinned); in Column 2, 472 (471 for the browsers); in Column 3, 471, 473 and 472; in Column 4, 471 (470 for the browsers, 469 with Math pinned, 472 for Safari’s screen). Columns 2–4: green below 1%, orange 1% or more, dash not run.
Table 4.
Games that end differently, in % of the games that finish in the cell’s runs: in Column 1, 473 (472 with Math pinned); in Column 2, 472 (471 for the browsers); in Column 3, 471, 473 and 472; in Column 4, 471 (470 for the browsers, 469 with Math pinned, 472 for Safari’s screen). Columns 2–4: green below 1%, orange 1% or more, dash not run.
| No fix | Step 1 | Step 2 | Both | |
|---|---|---|---|---|
| Setting changed | (1) | (2) | (3) | (4) |
| Browser, at least one pair | 7.0 | 8.9 | 1.5 | 1.3 |
| with Math pinned | 5.9 | – | – | 0.4 |
| Screen, Safari | 7.0 | 0.4 | 6.8 | 0.0 |
| Screen, Chrome | 7.0 | 0.0 | – | 0.0 |
| Stage, Chrome | 7.0 | 0.0 | – | 0.0 |
| Graphics path, Chrome | 0.6 | 0.4 | – | 0.0 |
| Canvas path, Chrome 154 | 3.0 | – | – | 0.2 |
| Computer, Chrome 154 | 2.5 | – | – | 0.2 |
| Chrome – Safari | 9.1 | 6.4 | 7.4 | 0.4 |
Disclaimer/Publisher’s Note: The statements, opinions and data contained in all publications are solely those of the individual author(s) and contributor(s) and not of MDPI and/or the editor(s). MDPI and/or the editor(s) disclaim responsibility for any injury to people or property resulting from any ideas, methods, instructions or products referred to in the content. |
© 2026 by the authors. Licensee MDPI, Basel, Switzerland. This article is an open access article distributed under the terms and conditions of the Creative Commons Attribution (CC BY) license (http://creativecommons.org/licenses/by/4.0/).
Copyright: This open access article is published under a Creative Commons CC BY 4.0 license, which permit the free download, distribution, and reuse, provided that the author and preprint are cited in any reuse.