Discuss Scratch
- Discussion Forums
- » Advanced Topics
- » Parsing the project.json
- -EmeraldThunder-
-
Scratcher
1000+ posts
Parsing the project.json
Recently I have been trying to make a project that involves parsing a certain blockstack from the project.json.
The only problem is the json is terribly cryptic
How can I decode the when flag clicked blockstack from this into a javascript object with an operation key as the name of each custom block and an inputs array with the decoded text of each input. How can I achieve this using vanilla javascript.
The code this represents is simply:

The only problem is the json is terribly cryptic
{"targets":[{"isStage":true,"name":"Stage","variables":{},"lists":{},"broadcasts":{},"blocks":{"UWAQRO#JH($,v]k]*%t-":{"opcode":"procedures_definition","next":null,"parent":null,"inputs":{"custom_block":[1,"eGs#PRQt$[c{JaBw.Ycy"]},"fields":{},"shadow":false,"topLevel":true,"x":44,"y":-814},"eGs#PRQt$[c{JaBw.Ycy":{"opcode":"procedures_prototype","next":null,"parent":"UWAQRO#JH($,v]k]*%t-","inputs":{"6*`%0%3taVb_0K@8S6j{":[1,"FVjWl{@Q7{EKrqu^BM[a"]},"fields":{},"shadow":true,"topLevel":false,"mutation":{"tagName":"mutation","children":[],"proccode":"Add text %s","argumentids":"[\"6*`%0%3taVb_0K@8S6j{\"]","argumentnames":"[\"text\"]","argumentdefaults":"[\"\"]","warp":"true"}},"FVjWl{@Q7{EKrqu^BM[a":{"opcode":"argument_reporter_string_number","next":null,"parent":"eGs#PRQt$[c{JaBw.Ycy","inputs":{},"fields":{"VALUE":["text",null]},"shadow":true,"topLevel":false},":F#RYjH/Z`PLC4{HVquV":{"opcode":"procedures_call","next":null,"parent":null,"inputs":{"6*`%0%3taVb_0K@8S6j{":[1,[10,"Scratch!"]]},"fields":{},"shadow":false,"topLevel":true,"x":49,"y":-667,"mutation":{"tagName":"mutation","children":[],"proccode":"Add text %s","argumentids":"[\"6*`%0%3taVb_0K@8S6j{\"]","warp":"true"}}},"comments":{},"currentCostume":0,"costumes":[{"assetId":"cd21514d0531fdffb22204e0ec5ed84a","name":"backdrop1","md5ext":"cd21514d0531fdffb22204e0ec5ed84a.svg","dataFormat":"svg","rotationCenterX":240,"rotationCenterY":180}],"sounds":[{"assetId":"83a9787d4cb6f3b7632b4ddfebf74367","name":"pop","dataFormat":"wav","format":"","rate":48000,"sampleCount":1123,"md5ext":"83a9787d4cb6f3b7632b4ddfebf74367.wav"}],"volume":100,"layerOrder":0,"tempo":60,"videoTransparency":50,"videoState":"on","textToSpeechLanguage":null}],"monitors":[],"extensions":[],"meta":{"semver":"3.0.0","vm":"0.2.0-prerelease.20210811102104","agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.131 Safari/537.36 Edg/92.0.902.67"}}
The code this represents is simply:

Last edited by -EmeraldThunder- (Aug. 13, 2021 07:02:04)
- Pufferfish_Test
-
Scratcher
500+ posts
Parsing the project.json
Take a look at https://en.scratch-wiki.info/wiki/Scratch_File_Format for the sb3 ‘specification’ and https://github.com/LLK/scratch-vm/blob/develop/src/serialization/sb3.js for an example of how scratch parses the project.json.
- -EmeraldThunder-
-
Scratcher
1000+ posts
Parsing the project.json
Take a look at https://en.scratch-wiki.info/wiki/Scratch_File_Format for the sb3 ‘specification’ and https://github.com/LLK/scratch-vm/blob/develop/src/serialization/sb3.js for an example of how scratch parses the project.json.Thank you these resources seem to be rather helpful, I will read them properly later.
- imfh
-
Scratcher
1000+ posts
Parsing the project.json
Well, first of all you’ll want to prettify the json. That should help you make a little more sense of the garbled mess:
Then you’ll need to loop through each target and find the sprite you want. Then you’ll need to loop through the targets blocks until you find the green flag. Then you’ll need to loop through each block under the green flag and parse it. Roughly in pseudo code:
{ "targets":[ { "isStage":true, "name":"Stage", "variables":{ }, "lists":{ }, "broadcasts":{ }, "blocks":{ "UWAQRO#JH($,v]k]*%t-":{ "opcode":"procedures_definition", "next":null, "parent":null, "inputs":{ "custom_block":[ 1, "eGs#PRQt$[c{JaBw.Ycy" ] }, "fields":{ }, "shadow":false, "topLevel":true, "x":44, "y":-814 }, "eGs#PRQt$[c{JaBw.Ycy":{ "opcode":"procedures_prototype", "next":null, "parent":"UWAQRO#JH($,v]k]*%t-", "inputs":{ "6*`%0%3taVb_0K@8S6j{":[ 1, "FVjWl{@Q7{EKrqu^BM[a" ] }, "fields":{ }, "shadow":true, "topLevel":false, "mutation":{ "tagName":"mutation", "children":[ ], "proccode":"Add text %s", "argumentids":"[\"6*`%0%3taVb_0K@8S6j{\"]", "argumentnames":"[\"text\"]", "argumentdefaults":"[\"\"]", "warp":"true" } }, "FVjWl{@Q7{EKrqu^BM[a":{ "opcode":"argument_reporter_string_number", "next":null, "parent":"eGs#PRQt$[c{JaBw.Ycy", "inputs":{ }, "fields":{ "VALUE":[ "text", null ] }, "shadow":true, "topLevel":false }, ":F#RYjH/Z`PLC4{HVquV":{ "opcode":"procedures_call", "next":null, "parent":null, "inputs":{ "6*`%0%3taVb_0K@8S6j{":[ 1, [ 10, "Scratch!" ] ] }, "fields":{ }, "shadow":false, "topLevel":true, "x":49, "y":-667, "mutation":{ "tagName":"mutation", "children":[ ], "proccode":"Add text %s", "argumentids":"[\"6*`%0%3taVb_0K@8S6j{\"]", "warp":"true" } } }, "comments":{ }, "currentCostume":0, "costumes":[ { "assetId":"cd21514d0531fdffb22204e0ec5ed84a", "name":"backdrop1", "md5ext":"cd21514d0531fdffb22204e0ec5ed84a.svg", "dataFormat":"svg", "rotationCenterX":240, "rotationCenterY":180 } ], "sounds":[ { "assetId":"83a9787d4cb6f3b7632b4ddfebf74367", "name":"pop", "dataFormat":"wav", "format":"", "rate":48000, "sampleCount":1123, "md5ext":"83a9787d4cb6f3b7632b4ddfebf74367.wav" } ], "volume":100, "layerOrder":0, "tempo":60, "videoTransparency":50, "videoState":"on", "textToSpeechLanguage":null } ], "monitors":[ ], "extensions":[ ], "meta":{ "semver":"3.0.0", "vm":"0.2.0-prerelease.20210811102104", "agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.131 Safari/537.36 Edg/92.0.902.67" } }
for target in sb3.targets:
if target.name == "my name":
break
doesn't check if the target was actually found
for block in target.blocks:
if block.opcode == "event_whenflagclicked":
break
doesn't check if the green flag was actually found
blockid = block.next
while blockid is not None:
block = target.blocks[blockid]
doesn't check if the block is actually a custom block call
get all of the name up to the first argument
name = block.mutation.proccode.split("%")
name will probably have a space on the end you’ll want to remove
input_names = decode_json(block.mutation.argumentnames)
do something with all this info
blockid = block.next
Last edited by imfh (Aug. 13, 2021 12:12:58)
- -EmeraldThunder-
-
Scratcher
1000+ posts
Parsing the project.json
What encoding format are the block names and inputs using, anything I try to decode them fails.
- imfh
-
Scratcher
1000+ posts
Parsing the project.json
What encoding format are the block names and inputs using, anything I try to decode them fails.The argument names lists is encoded with json. Did you try the JavaScript function JSON.parse()?
Edit: The custom block arguments, that is. If you’re talking about block opcodes and inputs, not custom blocks arguments, the blocks should already be decoded.
Last edited by imfh (Aug. 13, 2021 12:45:49)
- Discussion Forums
- » Advanced Topics
-
» Parsing the project.json