Discuss Scratch

redspacecat
Scratcher
500+ posts

Firefox runs projects at ~22 fps.

I'm pretty this is a dupe…

Does anyone know a fix I can use for projects on Firefox running slowly? (Around 20-22 frames per second)
Someone mentioned that they fixed it using a userscript here, but they can't share it.

If you have any ideas, please mention them.
BigNate469
Scratcher
1000+ posts

Firefox runs projects at ~22 fps.

Yeah, I've definitely seen this reported before, although I don't remember where.

I will say that it doesn't seem to be just an issue with Scratch, and that window.setInterval() in Firefox seems to have larger issues.
scratchcode1_2_3
Scratcher
1000+ posts

Firefox runs projects at ~22 fps.

im pretty sure its because firefox uses spidermonkey js interpreter instead of V8 like chromium.

ive also heard people talk about a nextdns or smth
redspacecat
Scratcher
500+ posts

Firefox runs projects at ~22 fps.

scratchcode1_2_3 wrote:

ive also heard people talk about a nextdns or smth
I don't see how NextDNS could possibly be related, and I'm not getting the error being reported there.
redspacecat
Scratcher
500+ posts

Firefox runs projects at ~22 fps.

bump
WindowsAdmin
Scratcher
1000+ posts

Firefox runs projects at ~22 fps.

scratchcode1_2_3 wrote:

ive also heard people talk about a nextdns or smth
A DNS shouldn't affect the fps but it can affect the loading times
scratchcode1_2_3
Scratcher
1000+ posts

Firefox runs projects at ~22 fps.

WindowsAdmin wrote:

scratchcode1_2_3 wrote:

ive also heard people talk about a nextdns or smth
A DNS shouldn't affect the fps but it can affect the loading times
Yeah idk people keep quoting me on this but I heard it, not that I know what it means.
davidtheplatform
Scratcher
500+ posts

Firefox runs projects at ~22 fps.

Interestingly this doesn’t happen on Linux, at least not for me
o97doge
Scratcher
500+ posts

Firefox runs projects at ~22 fps.

davidtheplatform wrote:

(#8)
Interestingly this doesn’t happen on Linux, at least not for me
Neither with me on MacOS. (Although I'm using Firefox Nightly)
nembence
Scratcher
500+ posts

Firefox runs projects at ~22 fps.

CST1229 in the topic you linked wrote:

I once experimented with finding a fix for this. I made the runtime use JavaScript's requestAnimationFrame function instead of setInterval to time frames, and it went from ~21FPS to ~30FPS for me (though I implemented it as a userscript so I sadly can't share it here).
If you overwrite window.setInterval and window.clearInterval with something, then Scratch will use that.
Here is a workaround for setInterval using requestAnimationFrame:
(the broadcasts mean requestAnimationFrame)
define setInterval {function [...args]::custom-arg} (delay) (...args)
var (nextTime) (intervalID) @delInput @addInput::grey
set [intervalID v] to (next interval ID::sensing)
add (intervalID) to [ids v]
define {
when I receive [first frame v] (timer)::events hat
set [nextTime v] to ((timer)+(delay::custom-arg))
broadcast (repeat v)
}::stack
define {
when I receive [repeat v] (timer)::events hat
if <[ids v] contains (intervalID) ?> then
broadcast (repeat v)
if <(timer) \> (nextTime)> then
while <(timer) \> (nextTime)> {
change [nextTime v] by (delay::custom-arg)
}::control
function (...args::custom-arg)::custom
end
end
}::stack
broadcast (first frame v)
return (intervalID)::custom cap
define clearInterval (ID)
if <[ids v] contains (ID)?> then
delete (item # of (ID) in [ids v]) of [ids v]
else
clearInterval (ID)::sensing // make sure to use the original function and not the replacement
end
redspacecat
Scratcher
500+ posts

Firefox runs projects at ~22 fps.

nembence wrote:

CST1229 in the topic you linked wrote:

I once experimented with finding a fix for this. I made the runtime use JavaScript's requestAnimationFrame function instead of setInterval to time frames, and it went from ~21FPS to ~30FPS for me (though I implemented it as a userscript so I sadly can't share it here).
If you overwrite window.setInterval and window.clearInterval with something, then Scratch will use that.
Here is a workaround for setInterval using requestAnimationFrame:
(the broadcasts mean requestAnimationFrame)
define setInterval {function [...args]::custom-arg} (delay) (...args)
var (nextTime) (intervalID) @delInput @addInput::grey
set [intervalID v] to (next interval ID::sensing)
add (intervalID) to [ids v]
define {
when I receive [first frame v] (timer)::events hat
set [nextTime v] to ((timer)+(delay::custom-arg))
broadcast (repeat v)
}::stack
define {
when I receive [repeat v] (timer)::events hat
if <[ids v] contains (intervalID) ?> then
broadcast (repeat v)
if <(timer) \> (nextTime)> then
while <(timer) \> (nextTime)> {
change [nextTime v] by (delay::custom-arg)
}::control
function (...args::custom-arg)::custom
end
end
}::stack
broadcast (first frame v)
return (intervalID)::custom cap
define clearInterval (ID)
if <[ids v] contains (ID)?> then
delete (item # of (ID) in [ids v]) of [ids v]
else
clearInterval (ID)::sensing // make sure to use the original function and not the replacement
end
I'll try implementing it sometime and see if I can figure it out
This is a bit confusing because it's written in scratchblocks…
redspacecat
Scratcher
500+ posts

Firefox runs projects at ~22 fps.

nembence wrote:

CST1229 in the topic you linked wrote:

I once experimented with finding a fix for this. I made the runtime use JavaScript's requestAnimationFrame function instead of setInterval to time frames, and it went from ~21FPS to ~30FPS for me (though I implemented it as a userscript so I sadly can't share it here).
If you overwrite window.setInterval and window.clearInterval with something, then Scratch will use that.
Here is a workaround for setInterval using requestAnimationFrame:
(the broadcasts mean requestAnimationFrame)
~scratchblocks snip~
Where is “Next interval id” coming from?

Last edited by redspacecat (Jan. 27, 2025 15:36:26)

CST1229
Scratcher
1000+ posts

Firefox runs projects at ~22 fps.

nembence wrote:

(#10)
If you overwrite window.setInterval and window.clearInterval with something, then Scratch will use that.
That is exactly what my userscript does (though with a bit of extra safety code to ensure only Scratch's interval is affected). I would share it if I was able to.

Last edited by CST1229 (Jan. 27, 2025 16:33:47)

nembence
Scratcher
500+ posts

Firefox runs projects at ~22 fps.

redspacecat wrote:

nembence wrote:

~snip~
Where is “Next interval id” coming from?
You can get the first ID by creating a built-in interval and deleting it, then just increment it in a variable to always get a new one
scratchcode1_2_3
Scratcher
1000+ posts

Firefox runs projects at ~22 fps.

nembence wrote:

CST1229 in the topic you linked wrote:

I once experimented with finding a fix for this. I made the runtime use JavaScript's requestAnimationFrame function instead of setInterval to time frames, and it went from ~21FPS to ~30FPS for me (though I implemented it as a userscript so I sadly can't share it here).
If you overwrite window.setInterval and window.clearInterval with something, then Scratch will use that.
Here is a workaround for setInterval using requestAnimationFrame:
(the broadcasts mean requestAnimationFrame)
define setInterval {function [...args]::custom-arg} (delay) (...args)
var (nextTime) (intervalID) @delInput @addInput::grey
set [intervalID v] to (next interval ID::sensing)
add (intervalID) to [ids v]
define {
when I receive [first frame v] (timer)::events hat
set [nextTime v] to ((timer)+(delay::custom-arg))
broadcast (repeat v)
}::stack
define {
when I receive [repeat v] (timer)::events hat
if <[ids v] contains (intervalID) ?> then
broadcast (repeat v)
if <(timer) \> (nextTime)> then
while <(timer) \> (nextTime)> {
change [nextTime v] by (delay::custom-arg)
}::control
function (...args::custom-arg)::custom
end
end
}::stack
broadcast (first frame v)
return (intervalID)::custom cap
define clearInterval (ID)
if <[ids v] contains (ID)?> then
delete (item # of (ID) in [ids v]) of [ids v]
else
clearInterval (ID)::sensing // make sure to use the original function and not the replacement
end
did…. you… just write JavaScript in scratchblocks?
JakubMzTrencina
Scratcher
100+ posts

Firefox runs projects at ~22 fps.

Scratch projects seem to run fine via Firefox on Linux, tested on Ubuntu and Debian. This might be a Windows-only problem.
PaxtonPenguin
Scratcher
100+ posts

Firefox runs projects at ~22 fps.

JakubMzTrencina wrote:

Scratch projects seem to run fine via Firefox on Linux, tested on Ubuntu and Debian. This might be a Windows-only problem.
I use firefox on windows and it works (although i do also use nightly so they might have fixed it)
redspacecat
Scratcher
500+ posts

Firefox runs projects at ~22 fps.

PaxtonPenguin wrote:

JakubMzTrencina wrote:

Scratch projects seem to run fine via Firefox on Linux, tested on Ubuntu and Debian. This might be a Windows-only problem.
I use firefox on windows and it works (although i do also use nightly so they might have fixed it)
Still happening to me using regular version

My browser / operating system: Windows NT 10.0 (actually 11), Firefox 134.0.2, No Flash version detected

Last edited by redspacecat (Jan. 28, 2025 15:23:02)

redspacecat
Scratcher
500+ posts

Firefox runs projects at ~22 fps.

Update: I managed to get ChatGPT to give me a working solution!

I don't think sharing my prompt counts as sharing a userscript, but tell me if it does.

Here's my prompt:

Use this scratchblocks code to create a javascript script to fix Scratch running projects at 22 fps

I once experimented with finding a fix for this. I made the runtime use JavaScript's requestAnimationFrame function instead of setInterval to time frames, and it went from ~21FPS to ~30FPS for me (though I implemented it as a userscript so I sadly can't share it here).[/quote]
If you overwrite window.setInterval and window.clearInterval with something, then Scratch will use that.
Here is a workaround for setInterval using requestAnimationFrame:
(the broadcasts mean requestAnimationFrame)
[scratchblocks]
define setInterval {function [...args]::custom-arg} (delay) (...args)
var (nextTime) (intervalID) @delInput @addInput::grey
set [intervalID v] to (next interval ID::sensing)
add (intervalID) to [ids v]
define {
when I receive [first frame v] (timer)::events hat
set [nextTime v] to ((timer)+(delay::custom-arg))
broadcast (repeat v)
}::stack
define {
when I receive [repeat v] (timer)::events hat
if <[ids v] contains (intervalID) ?> then
broadcast (repeat v)
if <(timer) \> (nextTime)> then
while <(timer) \> (nextTime)> {
change [nextTime v] by (delay::custom-arg)
}::control
function (...args::custom-arg)::custom
end
end
}::stack
broadcast (first frame v)
return (intervalID)::custom cap
define clearInterval (ID)
if <[ids v] contains (ID)?> then
delete (item # of (ID) in [ids v]) of [ids v]
else
clearInterval (ID)::sensing // make sure to use the original function and not the replacement
end


Edit: to fix the fact that the fps jumps back to around 60 when refocusing the tab, I prompted it a bit more along the lines of:
That still didn't fix it. The fps still jumps to around 60 briefly when coming back to the tab

Last edited by redspacecat (May 17, 2025 03:00:41)

Powered by DjangoBB