Discuss Scratch

MonkeyBean2
Scratcher
500+ posts

Alternative to popular method of accessing scratch VM object that longer works

The popular method of grabbing the scratch VM object from the project editor page no longer works (as of 2025-10-11):
let vm = document.getElementById('app')._reactRootContainer._internalRoot
.current.child.pendingProps.store.getState().scratchGui.vm
(note: if someone remembers who made this originally, please tell me so I can credit them)

This was very useful for messing around with nonstandard project JSON – Once you have the VM object, use vm.toJSON() and vm.loadProject() to export/import the project in JSON form (much faster than downloading/uploading the .sb3 (although you can upload project.json directly)).

I have come up with a new method that appears to work (however I wouldn't be surprised if it breaks in the near future, as subtle changes could break it).
let vm = Object.entries(document.getElementById('app').children[0])
.find(x=>x[0].startsWith("__reactFiber$"))[1].return.return.return.return
.pendingProps.value.store.getState().scratchGui.vm

I found this by searching through the JSON objects of every HTML element on the project page for a key named ‘store’.

It uses .find() (.filter but it outputs only the first match) because the __reactFiber$… key has a random ID at the end.

note to ST: This code does not actually do anything, it merely indexes through the object tree to find the scratch-vm object.

Maximouse
Scratcher
1000+ posts

Alternative to popular method of accessing scratch VM object that longer works

Here's a slightly shorter version:
let vm = Object.entries(document.getElementById('app'))
.find(x=>x[0].startsWith("__reactContainer$"))[1].child
.pendingProps.store.getState().scratchGui.vm

MonkeyBean2 wrote:

(note: if someone remembers who made this originally, please tell me so I can credit them)
I believe it's by @completeness: https://scratch.mit.edu/discuss/post/6180624/
Geotale
Scratcher
100+ posts

Alternative to popular method of accessing scratch VM object that longer works

Further shorter versions, found via thorough searching:
/// Option 1
Object.values(document.getElementById('app'))[0].child.updateQueue.lastEffect.deps[1].scratchGui.vm
// Option 2, for fun
Object.values(document.querySelector(".project-info-alerts").nextSibling.firstChild)[0].child.pendingProps.vm 
redspacecat
Scratcher
1000+ posts

Alternative to popular method of accessing scratch VM object that longer works

Maximouse wrote:

MonkeyBean2 wrote:

(note: if someone remembers who made this originally, please tell me so I can credit them)
I believe it's by @completeness: https://scratch.mit.edu/discuss/post/6180624/
For reference, the original post got dust binned for some reason.
It's still on ocular though: https://ocular.jeffalo.net/post/6180083
nembence
Scratcher
500+ posts

Alternative to popular method of accessing scratch VM object that longer works

This feels more reliable than doing hard-coded property accesses, although I don't know if it really is. It seems to work on the project page, in the editor, and on the new scratch-gui website (it doesn't work on the old scratch-gui website because that has “__reactInternalInstance###” instead of “__reactFiber###”, but it works if you replace “/Fiber/” with “/Instance/” or “/Fiber|Instance/”)
let fiber=Object.entries(document.querySelector('[class*="stage-wrapper"]')).find(x=>/Fiber/.test(x))[1];
while(!fiber.pendingProps.vm) fiber=fiber.return;
let vm=fiber.pendingProps.vm;

Also here is a shortened version:
let vm = (a=>a=f=>f.pendingProps.vm||a(f.return))()(
  Object.entries(document.querySelector('[class*="stage-wrapper"]')).find(x=>/Fiber/.test(x))[1]
);

To get the “store” object replace all “vm”-s in the code with “store”

Powered by DjangoBB