0t# Working with Second Representation in pmp_manip
This is the UML structure of a SRProject:
Let us compare an SRProject with it's view in the PenguinMod Editor
from pmp_manip import get_default_config, init_config, FRProject, info_api
cfg = get_default_config()
init_config(cfg)
frproject = FRProject.from_file(file_path="path/to/my_project.pmp")
frproject.add_all_extensions_to_info_api(info_api)
srproject = frproject.to_second(info_api)
print("The contents of the project are:")
print(srproject)Note: add_all_extensions_to_info_api is discussed later in the tutorial
Output (very long, you can skim it for now. Is analyzed in detail later):
The contents of the project are:
SRProject(
stage=SRStage(
scripts=[],
comments=[],
costumes=[
SRVectorCostume(
content=<Element {http://www.w3.org/2000/svg}svg at 0x7820d9c840>,
name="backdrop1",
file_extension="svg",
rotation_center=(240, 180),
),
],
sounds=[],
costume_index=0,
volume=100,
),
sprites=[
SRSprite(
name="Abby",
local_variables=[
SRVariable(name="my slider var", current_value=30.9),
SRVariable(name="another local var", current_value="General Kenobi!"),
],
local_lists=[
SRList(name="a local list", current_value=[]),
],
local_monitors=[
SRMonitor(
opcode="&sensing::draggable?",
dropdowns={},
position=(-240, 16),
is_visible=True,
),
SRVariableMonitor(
readout_mode=SRVariableMonitorReadoutMode.SLIDER,
slider_min=30.9,
slider_max=100,
allow_only_integers=False,
opcode="&variables::value of [VARIABLE]",
dropdowns={
"VARIABLE": SRDropdownValue(kind=DropdownValueKind.VARIABLE, value="my slider var"),
},
position=(-240, -54),
is_visible=True,
),
SRMonitor(
opcode="&looks::[EFFECT] effect",
dropdowns={
"EFFECT": SRDropdownValue(kind=DropdownValueKind.STANDARD, value="color"),
},
position=(-240, -14),
is_visible=True,
),
SRVariableMonitor(
readout_mode=SRVariableMonitorReadoutMode.LARGE,
slider_min=0,
slider_max=100,
allow_only_integers=True,
opcode="&variables::value of [VARIABLE]",
dropdowns={
"VARIABLE": SRDropdownValue(kind=DropdownValueKind.VARIABLE, value="another local var"),
},
position=(-240, -80),
is_visible=True,
),
SRListMonitor(
size=(100, 102),
opcode="&variables::value of [LIST]",
dropdowns={
"LIST": SRDropdownValue(kind=DropdownValueKind.LIST, value="a local list"),
},
position=(-240, 78),
is_visible=True,
),
],
is_visible=True,
position=(39, 3),
size=150,
direction=90,
is_draggable=True,
uuid=UUID('a1e32a92-36fa-4a45-bc2e-9c1eca536a30'),
scripts=[
SRScript(
position=(235, 79),
blocks=[
SRBlock(
opcode="&customblocks::define custom block",
inputs={},
dropdowns={},
comment=None,
mutation=SRCustomBlockMutation(
custom_opcode=SRCustomBlockOpcode(
segments=(
"run frame with speed",
SRCustomBlockArgument(name="speed", type=SRCustomBlockArgumentType.STRING_NUMBER),
"handle keys?",
SRCustomBlockArgument(name="handle keys", type=SRCustomBlockArgumentType.BOOLEAN),
),
),
no_screen_refresh=True,
optype=SRCustomBlockOptype.STATEMENT,
main_color="#FF6680",
prototype_color="#e65c73",
outline_color="#cc5266",
),
),
SRBlock(
opcode="&control::if <CONDITION> then {THEN}",
inputs={
"CONDITION": SRBlockAndBoolInputValue(
block=SRBlock(
opcode="&operators::<OPERAND1> and <OPERAND2>",
inputs={
"OPERAND1": SRBlockAndBoolInputValue(
block=SRBlock(
opcode="&sensing::key ([KEY]) pressed?",
inputs={
"KEY": SRBlockAndDropdownInputValue(
block=None,
dropdown=SRDropdownValue(kind=DropdownValueKind.STANDARD, value="space"),
),
},
dropdowns={},
comment=None,
mutation=None,
),
immediate=False,
),
"OPERAND2": SRBlockAndBoolInputValue(
block=SRBlock(
opcode="&customblocks::custom block boolean arg [ARGUMENT]",
inputs={},
dropdowns={},
comment=None,
mutation=SRCustomBlockArgumentMutation(
argument_name="handle keys",
main_color="#FF6680",
prototype_color="#e65c73",
outline_color="#cc5266",
),
),
immediate=True,
),
},
dropdowns={},
comment=None,
mutation=None,
),
immediate=False,
),
"THEN": SRScriptInputValue(
blocks=[
SRBlock(
opcode="&looks::say (MESSAGE) for (SECONDS) seconds",
inputs={
"MESSAGE": SRBlockAndTextInputValue(block=None, immediate="Hello!"),
"SECONDS": SRBlockAndTextInputValue(block=None, immediate="2"),
},
dropdowns={},
comment=SRComment(
position=(544.2964344861196, 207.30042684993646),
size=(200, 200),
is_minimized=True,
text="not fully\nshown",
),
mutation=None,
),
SRBlock(
opcode="&looks::change [EFFECT] effect by (AMOUNT)",
inputs={
"AMOUNT": SRBlockAndTextInputValue(block=None, immediate="25"),
},
dropdowns={
"EFFECT": SRDropdownValue(kind=DropdownValueKind.STANDARD, value="color"),
},
comment=None,
mutation=None,
),
],
),
},
dropdowns={},
comment=None,
mutation=None,
),
],
),
SRScript(
position=(257, 714),
blocks=[
SRBlock(
opcode="&variables::set [VARIABLE] to (VALUE)",
inputs={
"VALUE": SRBlockAndTextInputValue(block=None, immediate="hello there!"),
},
dropdowns={
"VARIABLE": SRDropdownValue(kind=DropdownValueKind.VARIABLE, value="another glob var"),
},
comment=None,
mutation=None,
),
],
),
SRScript(
position=(240, 549),
blocks=[
SRBlock(
opcode="&customblocks::call custom block",
inputs={
"speed": SRBlockAndTextInputValue(block=None, immediate="2"),
"handle keys": SRBlockAndBoolInputValue(
block=SRBlock(
opcode="&operators::true,
inputs={},
dropdowns={},
comment=None,
mutation=None,
),
immediate=False,
),
},
dropdowns={},
comment=None,
mutation=SRCustomBlockCallMutation(
custom_opcode=SRCustomBlockOpcode(
segments=(
"run frame with speed",
SRCustomBlockArgument(name="speed", type=SRCustomBlockArgumentType.STRING_NUMBER),
"handle keys?",
SRCustomBlockArgument(name="handle keys", type=SRCustomBlockArgumentType.BOOLEAN),
),
),
),
),
],
),
],
comments=[
SRComment(
position=(870, 244),
size=(200, 200),
is_minimized=False,
text="an independent\n comment\nwhich\nis\nfully\nshown",
),
],
costumes=[
SRBitmapCostume(
content=<PIL.PngImagePlugin.PngImageFile image mode=P size=176x144 at 0x781e6b60c0>,
has_double_resolution=True,
name="costume1",
file_extension="png",
rotation_center=(88, 72),
),
SRVectorCostume(
content=<Element {http://www.w3.org/2000/svg}svg at 0x781e6c4200>,
name="Abby-a",
file_extension="svg",
rotation_center=(31, 100),
),
],
sounds=[
SRSound(name="Squawk", file_extension="wav", content=<pydub.audio_segment.AudioSegment object at 0x781e6bce90>),
],
costume_index=1,
volume=100,
),
SRSprite(
name="Cake",
local_variables=[],
local_lists=[],
local_monitors=[],
is_visible=True,
position=(47.88235294117649, -104.70588235294117),
size=80,
direction=90,
is_draggable=False,
uuid=UUID('9ea54f86-9f2a-4f8b-ab0d-3f5870004020'),
scripts=[],
comments=[],
costumes=[
SRVectorCostume(
content=<Element {http://www.w3.org/2000/svg}svg at 0x781ed7be80>,
name="cake-a",
file_extension="svg",
rotation_center=(64, 50),
),
],
sounds=[
SRSound(name="Birthday", file_extension="wav", content=<pydub.audio_segment.AudioSegment object at 0x781e68b8c0>),
],
costume_index=0,
volume=100,
),
SRSprite(
name="Apple",
local_variables=[],
local_lists=[],
local_monitors=[],
is_visible=True,
position=(60.58823529411765, -73.47058823529413),
size=150,
direction=90,
is_draggable=False,
uuid=UUID('1026712f-651e-43a1-9456-cf22e4555990'),
scripts=[],
comments=[],
costumes=[
SRVectorCostume(
content=<Element {http://www.w3.org/2000/svg}svg at 0x781e6b6d80>,
name="Apple",
file_extension="svg",
rotation_center=(31, 31),
),
],
sounds=[],
costume_index=0,
volume=100,
),
],
sprite_layer_stack=[
UUID('a1e32a92-36fa-4a45-bc2e-9c1eca536a30'),
UUID('1026712f-651e-43a1-9456-cf22e4555990'),
UUID('9ea54f86-9f2a-4f8b-ab0d-3f5870004020'),
],
global_variables=[
SRVariable(name="another glob var", current_value="hello there!"),
SRCloudVariable(name="☁ my cloud var", current_value="6772827383843273833275737871"),
],
global_lists=[
SRList(name="a global list", current_value=[345634, "some text"]),
SRList(name="another g. list", current_value=[389.41, 0]),
],
global_monitors=[
SRVariableMonitor(
readout_mode=SRVariableMonitorReadoutMode.NORMAL,
slider_min=0,
slider_max=100,
allow_only_integers=True,
opcode="&variables::value of [VARIABLE]",
dropdowns={
"VARIABLE": SRDropdownValue(kind=DropdownValueKind.VARIABLE, value="another glob var"),
},
position=(-240, -153),
is_visible=True,
),
SRVariableMonitor(
readout_mode=SRVariableMonitorReadoutMode.NORMAL,
slider_min=0,
slider_max=100,
allow_only_integers=True,
opcode="&variables::value of [VARIABLE]",
dropdowns={
"VARIABLE": SRDropdownValue(kind=DropdownValueKind.VARIABLE, value="☁ my cloud var"),
},
position=(-240, -180),
is_visible=True,
),
SRListMonitor(
size=(132, 219),
opcode="&variables::value of [LIST]",
dropdowns={
"LIST": SRDropdownValue(kind=DropdownValueKind.LIST, value="a global list"),
},
position=(108, -180),
is_visible=True,
),
SRListMonitor(
size=(100, 116),
opcode="&variables::value of [LIST]",
dropdowns={
"LIST": SRDropdownValue(kind=DropdownValueKind.LIST, value="another g. list"),
},
position=(140, 64),
is_visible=True,
),
SRMonitor(
opcode="&sensing::answer",
dropdowns={},
position=(-235, -25),
is_visible=False,
),
SRMonitor(
opcode="&sensing::current [PROPERTY]",
dropdowns={
"PROPERTY": SRDropdownValue(kind=DropdownValueKind.STANDARD, value="year"),
},
position=(-240, -128),
is_visible=True,
),
SRMonitor(
opcode="&sensing::timer,
dropdowns={},
position=(-240, -104),
is_visible=False,
),
],
extensions=[
SRBuiltinExtension(id="text2speech"),
SRCustomExtension(url="https://extensions.penguinmod.com/extensions/MubiLop/numutils.js", id="numberUtilities"),
],
tempo=60,
video_transparency=50,
video_state=SRVideoState.ON,
text_to_speech_language=SRTTSLanguage.ENGLISH,
)Notes:
- I highly recommend to use a good code editor (especially VSCode), because you might want to look at the definition of e.g. a function/method or class(
Alt+Left Mouse Click) - All listed properties and can be read, set and modified if not specified otherwise.
- Most classes are dataclasses (specified if not), which implement these features:
- Initialization (call class with all its properties set (listed below)) (e.g.
SRVariable(name="my variable", current_value=5)) - Comparison (
==) - Mutability (most, a few specified ones are immutable and hashable)
- Validation (
validatemethod, it is recommended to just validate theSRProjectas a whole => easiest, you will not need to pass in anything butinfo_api) - Conversion (most, with
to_firstmethods, it is recommended to just convert the project as a whole) - Nice Representation (defines a readable
__repr__) - Sorting (e.g. a
list[SomeSRThing])
- Initialization (call class with all its properties set (listed below)) (e.g.
The "root node" of a project in second representation.
- type:
listofSRSprite(subclass ofSRTarget) - description: The sprites of the project, excluding the stage.
- type:
listofUUID(from packageuuid) - description: The order of sprites on the stage. Must contain all sprite UUIDs(
SRSprite.uuid) in any order. Last UUID means sprite is on the highest layer and is rendered on top of all other sprites. First UUID means lowest layer.
- type:
listofSRVariableorSRCloudVariable(subclass) - description: The names and values of the "for all sprites" variables of the project. Local Variables are stored in specific sprites, see
SRSprite.local_variables.
- type:
listofSRList - description: The names and values of the "for all sprites" lists of the project. Local Lists are stored in specific sprites, see
SRSprite.local_lists
- type:
listofSRMonitor,SRVariableMonitor(subclass) andSRListMonitor(subclass) - description: The non-sprite-specific monitors of blocks shown or once shown on the stage. Local Monitors are stored in specific sprites, see
SRSprite.local_monitors.
- type:
listofSRBuiltinExtensionorSRCustomExtension, seeSRExtension(parent class) - description: Stores the ids and possibly urls/sources of all added extensions.
- type:
int(minimum:20, maximum:500) - description: The music "tempo" of Scratch's Music extension in BPM (insignificant for most projects).
- note: Equal to value of "tempo" block.
- default value in editor:
60
- type:
intorfloat(normally between0and100) (seems not to have limits by Scratch) - description: The "video transparency" of Scratch's Video Sensing extension (insignificant for most projects).
- note: Equal to input of "set video transparency to" block.
- default value in editor:
50
- type:
SRVideoState(enum class) - possible values:
SRVideoState.ON,SRVideoState.ON_FLIPPED,SRVideoState.OFF - description: The "state" of Scratch's Video Sensing extension (insignificant for most projects).
- note: Equal to dropdown menu of "turn video ..." block.
- default value in editor:
SRVideoState.ON
- type:
SRTTSLanguage(enum class) orNone - possible values:
SRTTSLanguage.ENGLISH,SRTTSLanguage.FRENCH,SRTTSLanguage.GERMAN... - description: The "text to speech language" of Scratch's TTS extension (insignificant for most projects).
- note: Equal to dropdown menu of "set language to" block.
- default value in editor:
None
SRProject(
stage=SRStage(
# shortend here
),
sprites=[
SRSprite(
name="Abby",
uuid=UUID('a1e32a92-36fa-4a45-bc2e-9c1eca536a30'),
# shortend here
),
SRSprite(
name="Cake",
uuid=UUID('9ea54f86-9f2a-4f8b-ab0d-3f5870004020'),
# shortend here
),
SRSprite(
name="Apple",
uuid=UUID('1026712f-651e-43a1-9456-cf22e4555990'),
# shortend here
),
],
sprite_layer_stack=[
UUID('a1e32a92-36fa-4a45-bc2e-9c1eca536a30'),
UUID('1026712f-651e-43a1-9456-cf22e4555990'),
UUID('9ea54f86-9f2a-4f8b-ab0d-3f5870004020'),
],
global_variables=[
SRVariable(name="another glob var", current_value="hello there!"),
SRCloudVariable(name="☁ my cloud var", current_value="6772827383843273833275737871"),
],
global_lists=[
SRList(name="a global list", current_value=[345634, "some text"]),
SRList(name="another g. list", current_value=[389.41, 0]),
],
global_monitors=[
SRVariableMonitor(
readout_mode=SRVariableMonitorReadoutMode.NORMAL,
slider_min=0,
slider_max=100,
allow_only_integers=True,
opcode="&variables::value of [VARIABLE]",
dropdowns={
"VARIABLE": SRDropdownValue(kind=DropdownValueKind.VARIABLE, value="another glob var"),
},
position=(-240, -153),
is_visible=True,
),
# shortend here
],
extensions=[
SRBuiltinExtension(id="text2speech"),
SRCustomExtension(url="https://extensions.penguinmod.com/extensions/MubiLop/numutils.js", id="numberUtilities"),
],
tempo=60,
video_transparency=50,
video_state=SRVideoState.ON,
text_to_speech_language=SRTTSLanguage.ENGLISH,
)- As we can see, all sprite UUIDs are contained in
sprite_layer_stack. The order is different though. E.G. The "Cake" Sprite is on top of "Apple" insprite_layer_stackbut not insprites.
Common base for SRStage and SRSprite.
- type:
listofSRScript - description: Stores all the blocks and attached comments in a sprite or the stage.
- type:
listofSRComment - description: Stores all the comments, which are not attached to a block, in a sprite or the stage.
- type:
listofSRVectorCostumeorSRBitmapCostume, seeSRCostume(parent class) - description: Stores all the costumes of a sprite or stage.
- note: Must have at least one costume(hint: use
SRVectorCostume.create_emptyfor an empty default costume)
- type:
listofSRSound - description: Stores all the sounds of a sprite or stage.
- type:
int(at least0and at most one less then the amount of costumes) - description: References the current costume of the sprite or stage in
costumesby index. - default value in editor:
0
- type:
int(minimum:0, maximum:100) - description: The local volume for playing sounds from a sprite or stage.
- default value in editor:
100
Represents the project stage. Inherits from SRTarget.
Has no additional properties compared to SRTarget, as all global information is stored on the project directly.
SRStage(
scripts=[],
comments=[],
costumes=[
SRVectorCostume(
content=<Element {http://www.w3.org/2000/svg}svg at 0x7820d9c840>,
name="backdrop1",
file_extension="svg",
rotation_center=(240, 180),
),
],
sounds=[],
costume_index=0,
volume=100,
)- As we can see, the stage has no scripts, comments and sounds, just one costume/backdrop which is empty.
- This costume is also referenced by costume index as it is item
0. - For a better example, see
SRSprite's Example.
Represents a sprite of the project. Inherits from SRTarget.
- type:
str(Blacklist:"_myself_","_stage_","_mouse_","_edge_") - description: The name of the sprite.
- type:
listofSRVariableorSRCloudVariable(subclass) - description: The names and values of the "for this sprite only" variables of the sprite. Global Variables are stored in the project directly, see
SRProject.global_variables.
- type:
listofSRList - description: The names and values of the "for this sprite only" lists of the sprite. Global Lists are stored in the project directly, see
SRProject.global_lists.
- type:
listofSRMonitor,SRVariableMonitor(subclass) andSRListMonitor(subclass) - description: The sprite-specific monitors of blocks shown or once shown on the stage. Global Monitors are stored in the project directly, see
SRProject.global_monitors.
- type:
bool - description: Stores wether the sprite is shown on the stage.
- default value in editor:
True
- type:
tupleofint|float(x position) andint|float(y position) - description: Stores the position of the sprite on the stage. If the stage size was not changed, should be between
(-240, -180)to(240, 180)(no enforced limit). - default value in editor: random
- type:
int | float(positive) - description: Stores the size of the sprite on the stage.
- default value in editor:
100
- type:
int | float(minimum:-180, maximum:-180) - description: Stores the rotation direction of the sprite on the stage.
- default value in editor:
90(Up:0, Right:90, Down:180, Left:-90)
- type:
bool - description: Stores wether the sprite can be dragged across the stage in fullscreen mode.
- default value in editor:
False
- type:
SRSpriteRotationStyle(enum class) - possible values:
SRSpriteRotationStyle.ALL_AROUND,SRSpriteRotationStyle.LEFT_RIGHT,SRSpriteRotationStyle.DONT_ROTATEin PenguinMod alsoSRSpriteRotationStyle.LOOK_AT,SRSpriteRotationStyle.UP_DOWN - description: The way the sprite behaves when rotated.
- default value in editor:
SRSpriteRotationStyle.ALL_AROUND
- type:
UUID(from packageuuid) - description: A unique id for the sprite. Only used for
SRProject.sprite_layer_stack. - note: Read-only. Can not be modified and can not be passed to
SRSpriteat Creation/Initialization, but is automatically set.
SRSprite(
name="Abby",
local_variables=[
SRVariable(name="my slider var", current_value=30.9),
SRVariable(name="another local var", current_value="General Kenobi!"),
],
local_lists=[
SRList(name="a local list", current_value=[]),
],
local_monitors=[
# shortend here
SRMonitor(
opcode="&looks::[EFFECT] effect",
dropdowns={
"EFFECT": SRDropdownValue(kind=DropdownValueKind.STANDARD, value="color"),
},
position=(-240, -14),
is_visible=True,
),
SRVariableMonitor(
readout_mode=SRVariableMonitorReadoutMode.LARGE,
slider_min=0,
slider_max=100,
allow_only_integers=True,
opcode="&variables::value of [VARIABLE]",
dropdowns={
"VARIABLE": SRDropdownValue(kind=DropdownValueKind.VARIABLE, value="another local var"),
},
position=(-240, -80),
is_visible=True,
),
SRListMonitor(
size=(100, 102),
opcode="&variables::value of [LIST]",
dropdowns={
"LIST": SRDropdownValue(kind=DropdownValueKind.LIST, value="a local list"),
},
position=(-240, 78),
is_visible=True,
),
],
is_visible=True,
position=(39, 3),
size=150,
direction=90,
is_draggable=True,
uuid=UUID('a1e32a92-36fa-4a45-bc2e-9c1eca536a30'),
scripts=[
SRScript(
position=(235, 79),
blocks=[
SRBlock(
opcode="&customblocks::define custom block",
inputs={},
dropdowns={},
comment=None,
mutation=SRCustomBlockMutation(
custom_opcode=SRCustomBlockOpcode(
segments=(
"run frame with speed",
SRCustomBlockArgument(name="speed", type=SRCustomBlockArgumentType.STRING_NUMBER),
"handle keys?",
SRCustomBlockArgument(name="handle keys", type=SRCustomBlockArgumentType.BOOLEAN),
),
),
no_screen_refresh=True,
optype=SRCustomBlockOptype.STATEMENT,
main_color="#FF6680",
prototype_color="#e65c73",
outline_color="#cc5266",
),
),
# shortend here
],
),
# shortend here
],
comments=[
SRComment(
position=(870, 244),
size=(200, 200),
is_minimized=False,
text="an independent\n comment\nwhich\nis\nfully\nshown",
),
],
costumes=[
SRBitmapCostume(
content=<PIL.PngImagePlugin.PngImageFile image mode=P size=176x144 at 0x781e6b60c0>,
has_double_resolution=True,
name="costume1",
file_extension="png",
rotation_center=(88, 72),
),
SRVectorCostume(
content=<Element {http://www.w3.org/2000/svg}svg at 0x781e6c4200>,
name="Abby-a",
file_extension="svg",
rotation_center=(31, 100),
),
],
sounds=[
SRSound(name="Squawk", file_extension="wav", content=<pydub.audio_segment.AudioSegment object at 0x781e6bce90>),
],
costume_index=1,
volume=100,
)- As we can see, the sprite has scripts, comments, two costumes(a vector and a bitmap costume) and a sound.
- The second and active costume is also referenced by costume index as it is item
1. - The local monitors are not normally seperated by position. They are arranged like this for simplicity in this tutorial.
Represents a "for all sprites"(global) or "for this sprite only"(local) variable.
- type:
str - description: The name of the variable.
- type: usually
int,floatorstr, but technicallybooltoo (e.g. Infinity is saved as 0). - description: The current value of the variable.
SRCloudVariable(name="☁ my cloud var", current_value="6772827383843273833275737871")SRVariable(name="another local var", current_value="General Kenobi!")SRVariable(name="my slider var", current_value=30.9)Inherits from SRVariable. Represents a cloud variable. Has no additional properties compared to SRVariable.
Represents a "for all sprites"(global) or "for this sprite only"(local) list.
- type:
str - description: The name of the list.
- type:
listof usuallyint,floatandstr, but technicallybooltoo (e.g. Infinity is saved as 0). - description: The current value of the list.
SRList(name="a global list", current_value=[345634, "some text"])SRList(name="another g. list", current_value=[389.41, 0])Represents a non-sprite-specific(global) or sprite-specific(local) monitor. Also is basis for SRVariableMonitor(subclass) and SRListMonitor(subclass)
- type:
str - description: The "opcode"(unique identifier) of the block, the monitor is for (see
SRBlock.opcode).
- type:
dictofstrkeys andSRDropdownValuevalues - description: the exact dropdown settings of the monitor (e.g. "costume number/name" block). Based on the dropdowns of the block (see
SRBlock.dropdowns).
- type:
tupleofint|float(x position) andint|float(y position) - description: Stores the position of the monitor on the stage. If the stage size was not changed, should be between
(-240, -180)to(240, 180)(no enforced limit). - note: You should change validation configuration to tolerant if you work with other stage sizes (See config.md, section ValidationConfig).
- type:
bool - description: Stores wether the monitor is currently shown on the stage.
SRMonitor(
opcode="&sensing::answer",
dropdowns={},
position=(-235, -25),
is_visible=False,
)SRMonitor(
opcode="&sensing::current [PROPERTY]",
dropdowns={
"PROPERTY": SRDropdownValue(kind=DropdownValueKind.STANDARD, value="year"),
},
position=(-240, -128),
is_visible=True,
)SRMonitor(
opcode="&sensing::timer",
dropdowns={},
position=(-240, -104),
is_visible=False,
)SRMonitor(
opcode="&looks::[EFFECT] effect",
dropdowns={
"EFFECT": SRDropdownValue(kind=DropdownValueKind.STANDARD, value="color"),
},
position=(-240, -14),
is_visible=True,
)- The "&sensing::answer" and "&sensing::timer" monitor is not shown and therefore not shown in the image.
- The keys of
dropdownsalways match with the sqaure brackets (e.g.[DROPDOWN]) in the opcode.
Represents the monitor of a variable value block of a global or local variable. Inherits from SRMonitor.
- type:
SRVariableMonitorReadoutMode(enum class) - possible values:
SRVariableMonitorReadoutMode.NORMAL,SRVariableMonitorReadoutMode.LARGE,SRVariableMonitorReadoutMode.SLIDER - description: Stores how a variable monitors is shown(e.g. only content(=
LARGE), name and content(=NORMAL), with a slider to change value(=SLIDER)) - default value in editor:
SRVariableMonitorReadoutMode.NORMAL
- type:
int | float - description: If
readout_modeisSLIDER, the minimum value you can drag the slider to. - default value in editor:
0
- type:
int | float - description: If
readout_modeisSLIDER, the maximum value you can drag the slider to. - default value in editor:
100
- type:
bool - description: If
readout_modeisSLIDER, wether you can drag the slider to a non-integer value. - note: is set in Scratch based on wether you enter a floating point value into either the slider minimum or maximum.
- default value in editor:
True
SRVariableMonitor(
readout_mode=SRVariableMonitorReadoutMode.NORMAL,
slider_min=0,
slider_max=100,
allow_only_integers=True,
opcode="&variables::value of [VARIABLE]",
dropdowns={
"VARIABLE": SRDropdownValue(kind=DropdownValueKind.VARIABLE, value="☁ my cloud var"),
},
position=(-240, -180),
is_visible=True,
)SRVariableMonitor(
readout_mode=SRVariableMonitorReadoutMode.SLIDER,
slider_min=30.9,
slider_max=100,
allow_only_integers=False,
opcode="&variables::value of [VARIABLE]",
dropdowns={
"VARIABLE": SRDropdownValue(kind=DropdownValueKind.VARIABLE, value="my slider var"),
},
position=(-240, -54),
is_visible=True,
)- The red/first monitor has
allow_only_integers=Trueas neitherslider_minnorslider_maxare both integers. - The blue/second monitor has
allow_only_integers=Falseasslider_minis a floating point number.
Represents the monitor of a list value block of a global or local list. Inherits from SRMonitor.
- type:
tupleofint|float(width) andint|float(height) - description: Stores the size of a list monitor as it can be resized.
- note: You should change validation configuration to tolerant if you work with other stage sizes (See config.md, section ValidationConfig).
- default value in editor:
(100, 120)
SRListMonitor(
size=(100, 102),
opcode="&variables::value of [LIST]",
dropdowns={
"LIST": SRDropdownValue(kind=DropdownValueKind.LIST, value="a local list"),
},
position=(-240, 78),
is_visible=True,
)Common base for SRBuiltinExtension and SRCustomExtension.
- type:
str - description: The unique id of the extension(e.g.
"music"or"jgJSON").
SRBuiltinExtension(id="text2speech")SRCustomExtension(
id="numberUtilities",
url="https://extensions.penguinmod.com/extensions/MubiLop/numutils.js",
)Represents a builtin extension that PenguinMod recognizes. Inherits from SRExtension.
Has no additional properties compared to SRExtension.
Represents a custom extension that PenguinMod does not recognize i.e. is added by URL, JS code or file. Therefore needs a url source. Inherits from SRExtension.
- type:
strz - description: The url source for getting the extension javascript source code. Must follow one of these patterns:
"http://...","https://..."or"data:application/javascript,..."
Enum Class. Represents a language for Scratch's Text to Speech Extension.
All supported languages are: SRTTSLanguage....
| enum name/language name | BCP 47 language code |
|---|---|
ARABIC |
"ar" |
CHINESE_MANDARIN |
"zh-cn" |
DANISH |
"da" |
DUTCH |
"nl" |
ENGLISH |
"en" |
FRENCH |
"fr" |
GERMAN |
"de" |
HINDI |
"hi" |
ICELANDIC |
"is" |
ITALIAN |
"it" |
JAPANESE |
"ja" |
KOREAN |
"ko" |
NORWEGIAN |
"nb" |
POLISH |
"pl" |
PORTUGUESE_BRAZILIAN |
"pt-br" |
PORTUGUESE |
"pt" |
ROMANIAN |
"ro" |
RUSSIAN |
"ru" |
SPANISH |
"es" |
SPANISH_LATIN_AMERICAN |
"es-419" |
SWEDISH |
"sv" |
TURKISH |
"tr" |
WELSH |
"cy" |
Represents a script i.e. a connected sequence of blocks in the "Code" tab of a sprite or the stage. Similar to SRScriptInputValue.
- type:
tupleofint|float(x position) andint|float(y position) Same system as withSRComment.position. - description: Stores the position of the script in the "Code" tab. Unlimited, but usually in the range of hundreds and thousands.
- type:
listofSRBlock - description: Stores the script's sequence of blocks from top to bottom.
SRScript(
position=(235, 79),
blocks=[
SRBlock(
opcode="&customblocks::define custom block",
inputs={},
dropdowns={},
comment=None,
mutation=SRCustomBlockMutation(
custom_opcode=SRCustomBlockOpcode(
segments=(
"run frame with speed",
SRCustomBlockArgument(
name="speed",
type=SRCustomBlockArgumentType.STRING_NUMBER,
),
"handle keys?",
SRCustomBlockArgument(
name="handle keys",
type=SRCustomBlockArgumentType.BOOLEAN,
),
),
),
no_screen_refresh=True,
optype=SRCustomBlockOptype.STATEMENT,
main_color="#FF6680",
prototype_color="#e65c73",
outline_color="#cc5266",
),
),
SRBlock(
opcode="&control::if <CONDITION> then {THEN}",
inputs={
"CONDITION": SRBlockAndBoolInputValue(
# shortend here
),
"THEN": SRScriptInputValue(
# shortend here
),
},
dropdowns={},
comment=None,
mutation=None,
),
],
)SRScript(
position=(420, 1022),
blocks=[
SRBlock(
opcode="&sensing::distance to ([OBJECT])",
inputs={
"OBJECT": SRBlockAndDropdownInputValue(
block=SRBlock(
opcode="&sound::length of ([SOUND])?",
inputs={
"SOUND": SRBlockAndDropdownInputValue(
block=None,
dropdown=SRDropdownValue(kind=DropdownValueKind.SOUND, value="Squawk"),
),
},
dropdowns={},
comment=None,
mutation=None,
),
dropdown=SRDropdownValue(kind=DropdownValueKind.SPRITE, value="Sprite2"),
),
},
dropdowns={},
comment=None,
mutation=None,
),
],
)- The second example is from another project.
- As the second example shows, even single reporter/boolean etc. blocks are seperate scripts.
Represents a single block in a script. Can be any shape of block(e.g. square, round, hat).
- type:
str - description: The unique identifier for it's kind of block.
- type:
dictofstrkeys andSRInputValuevalues (only of it's subclasses though) - description: The arguments fields of the block and their values. Includes text, number fields, round dropdowns one can insert blocks into and all others except for square dropdowns.
- type:
dictofstrkeys andSRDropdownValuevalues - description: The argument fields of the block and their values. Only includes square dropdowns, not round dropdowns one can insert blocks into.
- type:
SRCommentorNone - description: The optional attached comment of the block.
- default value in editor
:None`
- type:
SRMutationorNone - description: The optional mutation of the block for some opcodes(kinds of blocks). Most blocks do not need one.
- default value in editor
:None`
SRBlock(
opcode="&control::if <CONDITION> then {THEN}",
inputs={
"CONDITION": SRBlockAndBoolInputValue(
block=SRBlock(
opcode="&operators::<OPERAND1> and <OPERAND2>",
inputs={
"OPERAND1": SRBlockAndBoolInputValue(
# shortend, see below
),
"OPERAND2": SRBlockAndBoolInputValue(
# shortend, see below
),
},
dropdowns={},
comment=None,
mutation=None,
),
immediate=False,
),
"THEN": SRScriptInputValue(
blocks=[
# shortend, see below
],
),
},
dropdowns={},
comment=None,
mutation=None,
)SRBlockAndBoolInputValue(
block=SRBlock(
opcode="&operators::<OPERAND1> and <OPERAND2>",
inputs={
"OPERAND1": SRBlockAndBoolInputValue(
block=SRBlock(
opcode="&sensing::key ([KEY]) pressed?",
inputs={
"KEY": SRBlockAndDropdownInputValue(
block=None,
dropdown=SRDropdownValue(kind=DropdownValueKind.STANDARD, value="space"),
),
},
dropdowns={},
comment=None,
mutation=None,
),
immediate=False,
),
"OPERAND2": SRBlockAndBoolInputValue(
block=SRBlock(
opcode="&customblocks::custom block boolean arg [ARGUMENT]",
inputs={},
dropdowns={},
comment=None,
mutation=SRCustomBlockArgumentMutation(
argument_name="handle keys",
main_color="#FF6680",
prototype_color="#e65c73",
outline_color="#cc5266",
),
),
immediate=True,
),
},
dropdowns={},
comment=None,
mutation=None,
),
immediate=False,
)SRScriptInputValue(
blocks=[
SRBlock(
opcode="&looks::say (MESSAGE) for (SECONDS) seconds",
inputs={
"MESSAGE": SRBlockAndTextInputValue(block=None, immediate="Hello!"),
"SECONDS": SRBlockAndTextInputValue(block=None, immediate="2"),
},
dropdowns={},
comment=SRComment(
position=(544.2964344861196, 207.30042684993646),
size=(200, 200),
is_minimized=True,
text="not fully\nshown",
),
mutation=None,
),
SRBlock(
opcode="&looks::change [EFFECT] effect by (AMOUNT)",
inputs={
"AMOUNT": SRBlockAndTextInputValue(block=None, immediate="25"),
},
dropdowns={
"EFFECT": SRDropdownValue(kind=DropdownValueKind.STANDARD, value="color"),
},
comment=None,
mutation=None,
),
],
)- The python object is split for readability.
- As we can see, blocks and (sub-)scripts have a nested structure.
Represents a single input field of a block. Can be any kind of field (e.g. text, number, round dropdown) except for a square dropdown. Common base for
SRBlockAndTextInputValueSRBlockAndDropdownInputValueSRBlockAndBoolInputValueSRBlockOnlyInputValueSRScriptInputValueSREmbeddedBlockInputValue
these properties might but MUST NOT exist, the subclasses specify below which properties they support:
- type:
listofSRBlock - description: Stores the subscript's sequence of blocks from top to bottom (e.g. the "then" section of the "if" block).
- note: Only exists for instances of
SRScriptInputValue
- type:
SRBlockorNone - description: Stores the optional block inserted into the argument text field, round dropdown menu etc.
- note: Only exists for instances of
SRBlockAndTextInputValue,SRBlockAndDropdownInputValue,SRBlockOnlyInputValueandSREmbeddedBlockInputValue.
- type:
strorbool(depends on subclass) - description: the "immediate" value of the input value i.e. if the default value if no block is dragged into the input.
- note: Only exists for instances of
SRBlockAndTextInputValueandSRBlockAndBoolInputValue.
- type:
SRDropdownValue - description: Stores the round dropdown menu of the input value.
- note: Only exists for instances of
SRBlockAndDropdownInputValue.
See the example of SRBlock.
Inherits from SRInputValue.
- uses properties:
SRInputValue.block,SRInputValue.immediate
- type:
str(does not apply to other subclasses) - description: the "immediate" text value of the input value i.e. if the text default value if no block is dragged into the input.
- note:
strtype does not apply to other subclasses.
Inherits from SRInputValue.
- uses properties:
SRInputValue.block,SRInputValue.dropdown
Inherits from SRInputValue.
- uses properties:
SRInputValue.block,SRInputValue.immediate
- type:
bool(does not apply to other subclasses) - description: the "immediate" on/off switch value of the input value i.e. if the on/off switch default value if no block is dragged into the input.
Inherits from SRInputValue.
- uses properties:
SRInputValue.block
Inherits from SRInputValue. Similar to SRScript.
- uses properties:
SRInputValue.blocks
Inherits from SRInputValue. Must have a block. The opcode of that block is also constrained.
- uses properties:
SRInputValue.block
- type:
SRBlock, NOTNone - description: Stores the block inserted into the input. Must have one specific
opcode.
Represents a single dropdown field of a block. Can only be a square dropdown, which do not support inserting blocks into.
- type:
DropdownValueKind - description: Stores the kind of thing the dropdown value refers to (e.g.
VARIABLE,SPRITE,OBJECTorSTANDARD).
- type: almost always
strbut rarelyint(for costume, backdrop and sound selection by index) andbooltoo. - description: Stores the actual value of the dropdown value.
SRBlock(
opcode="&looks::change [EFFECT] effect by (AMOUNT)",
inputs={
"AMOUNT": SRBlockAndTextInputValue(block=None, immediate="25"),
},
dropdowns={
"EFFECT": SRDropdownValue(kind=DropdownValueKind.STANDARD, value="color"),
},
comment=None,
mutation=None,
)SRBlock(
opcode="&sensing::distance to ([OBJECT])",
inputs={
"OBJECT": SRBlockAndDropdownInputValue(
block=None,
dropdown=SRDropdownValue(kind=DropdownValueKind.OBJECT, value="mouse-pointer"),
),
},
dropdowns={},
comment=None,
mutation=None,
)- The second example is from another project.
Enum Class. Represents a kind of dropdown value i.e. what it references if anything.
All value kinds are: DropdownValueKind....
| enum name | reference |
|---|---|
STANDARD |
nothing |
SUGGESTION |
nothing |
FALLBACK |
nothing |
VARIABLE |
a variable |
LIST |
a list |
BROADCAST_MSG |
a broadcast message |
STAGE |
the stage |
SPRITE |
a sprite |
MYSELF |
the sprite the block is in |
OBJECT |
e.g. the mouse pointer, the stage edge |
COSTUME |
a costume of the current sprite by name(str value)or by index( int value) |
BACKDROP |
a backdrop by name(str value) or by index(int value) |
SOUND |
a sound by name(str value) or by index(int value) |
Stores additional information special to some kinds of blocks. Only needed for some block opcodes(kinds of blocks). Common base for:
SRCustomBlockArgumentMutationSRCustomBlockMutationSRCustomBlockCallMutationSRExpandableIfMutationSRExpandableOperatorMutationSRExpandableJoinMutation
Inherits from SRMutation. Used and required only by opcodes "&customblocks::custom block text arg [ARGUMENT]" and "customblocks::custom block boolean arg [ARGUMENT]".
- type:
str - description: the name of the custom block argument which the argument reporter block is for.
- type:
str(hex color code) - description: the main color of the "define" block the argument reporter block is for.
- default value in editor:
"#FF6680"
- type:
str(hex color code) - description: the main color of the inner block of the "define" block the argument reporter block is for.
- default value in editor:
"#FF4D6A"
- type:
str(hex color code) - description: the outline color of the inner block of the "define" block the argument reporter block is for.
- default value in editor:
"#FF3355"
The mutation itself can not be seen in the editor, only the block:

SRCustomBlockArgumentMutation(
argument_name="handle keys",
main_color="#FF6680",
prototype_color="#e65c73",
outline_color="#cc5266",
)Inherits from SRMutation. Used and required only by opcodes "&customblocks::define custom block" and "&customblocks::define custom block reporter".
- type:
SRCustomBlockOpcode(SRCustomBlockOpcodeis immutable and hashable) - description: Stores the name and argument field names and kinds of the custom block.
- type:
bool - description: Wether the "Run without screen refresh" box was ticked when creating the custom block.
- default value in editor:
False
- type:
SRCustomBlockOptype - description: What shape of block the custom block is (e.g. square statement, boolean, reporter).
- default value in editor:
SRCustomBlockMutation.STATEMENT
- type:
str(hex color code) - description: the main color of the "define" block.
- default value in editor:
"#FF6680"
- type:
str(hex color code) - description: the main color of the inner block of the "define" block.
- default value in editor:
"#FF4D6A"
- type:
str(hex color code) - description: the outline color of the inner block of the "define" block the argument reporter block is for.
- default value in editor:
"#FF3355"
The mutation itself can not be seen in the editor, only the block:

SRCustomBlockMutation(
custom_opcode=SRCustomBlockOpcode(
segments=(
"run frame with speed",
SRCustomBlockArgument(name="speed", type=SRCustomBlockArgumentType.STRING_NUMBER),
"handle keys?",
SRCustomBlockArgument(name="handle keys", type=SRCustomBlockArgumentType.BOOLEAN),
),
),
no_screen_refresh=True,
optype=SRCustomBlockOptype.STATEMENT,
main_color="#FF6680",
prototype_color="#e65c73",
outline_color="#cc5266",
)Inherits from SRMutation. Used and required only by opcode "&customblocks::call custom block".
- type:
SRCustomBlockOpcode(SRCustomBlockOpcodeis immutable and hashable) - description: Stores the labels and argument field names and kinds of the custom block, this block will call, to reference it.
The mutation itself can not be seen in the editor, only the block:

SRCustomBlockCallMutation(
custom_opcode=SRCustomBlockOpcode(
segments=(
"run frame with speed",
SRCustomBlockArgument(name="speed", type=SRCustomBlockArgumentType.STRING_NUMBER),
"handle keys?",
SRCustomBlockArgument(name="handle keys", type=SRCustomBlockArgumentType.BOOLEAN),
),
),
)Inherits from SRMutation. Used and required only by opcode "&control::{{EXPANDABLE IF-THEN-ELSE CHAIN}}".
- type:
int - description: the amount of branches
- type:
bool - description: wether the last branch is an else
The mutation itself can not be seen in the editor, only the block:

SRExpandableIfMutation(
branch_count=3,
ends_in_else=True,
)Inherits from SRMutation. Used and required only by opcodes "&operators::{{EXPANDABLE MATH CHAIN}}", "&operators::{{EXPANDABLE BOOL CHAIN}}", "&operators::{{EXPANDABLE COMPARE CHAIN}}".
- type:
listofSRExpandableOperatorMenu - description: the operations between the inputs
The mutation itself can not be seen in the editor, only the block:

SRExpandableOperatorMutation(
operations=[SRExpandableOperatorMenu.SUBTRACT, SRExpandableOperatorMenu.MULTIPLY],
)Inherits from SRMutation. Used and required only by opcode "&operators::{{EXPANDABLE JOIN CHAIN}}".
- type:
int(minimum:1) - description: the count of inputs
The mutation itself can not be seen in the editor, only the block:

SRExpandableJoinMutation(
input_count=4,
)Represents the "opcode"(see SRBlock.opcode) of a custom block i.e. stores the labels and argument field names and kinds of a custom block. Immutable and Hashable.
- type:
tupleofstrorSRCustomBlockArgument - description: Stores the labels and argument field names and kinds of the custom block. A
stritem represents a label, aSRCustomBlockArgumentrepresents an argument of the custom block.
Represents an argument of a SRCustomBlockOpcode. Immutable and Hashable.
- type:
str(not empty) - description: the name of the argument.
- type:
SRCustomBlockArgumentType(enum class) - possible values:
SRCustomBlockArgumentType.STRING_NUMBER,SRCustomBlockArgumentType.BOOLEAN - description: the kind of the argument (string or number vs. boolean).
Enum Class. Represents the shape of a custom block (e.g. square statement, boolean, reporter)
All possible values are: SRCustomBlockOptype....
| enum name |
|---|
STATEMENT |
ENDING_STATEMENT |
STRING_REPORTER |
NUMBER_REPORTER |
BOOLEAN_REPORTER |
Enum Class. Represents the dropdown values between the inputs of an expandable operator
All possible values are: SRExpandableOperatorMenu....
| enum name |
|---|
ADD |
SUBTRACT |
MULTIPLY |
DIVIDE |
POWER |
GREATER |
GREATER_EQ |
LESS |
LESS_EQ |
EQUAL |
STRICT_EQUAL |
NOT_EQUAL |
AND |
OR |
XOR |
NAND |
NOR |
XNOR |
Represents a comment, which can be either atttached to a block or "freely floating" in the "Code" tab of a sprite or the stage.
- type:
tupleofint|float(x position) andint|float(y position) - description: Stores the position of the comment in the "Code" tab. Unlimited, but usually in the range of hundreds and thousands. Same system as with
SRScript.position.
- type:
tupleofint|float(width) andint|float(height) minimum:(52, 32) - description: Stores the size of a comment.
- default value in editor:
(200, 200)
- type:
bool - description: Wether it is collapsed i.e. only a part of the comment is shown.
- default value in editor:
False
- type:
str - description: The actual text content of the comment.
SRComment(
position=(870, 244),
size=(200, 200),
is_minimized=False,
text="an independent\n comment\nwhich\nis\nfully\nshown",
)SRBlock(
opcode="&looks::say (MESSAGE) for (SECONDS) seconds",
inputs={
"MESSAGE": SRBlockAndTextInputValue(block=None, immediate="Hello!"),
"SECONDS": SRBlockAndTextInputValue(block=None, immediate="2"),
},
dropdowns={},
comment=SRComment(
position=(544.2964344861196, 207.30042684993646),
size=(200, 200),
is_minimized=True,
text="not fully\nshown",
),
mutation=None,
)Represents a costume in the "Costumes" tab of a sprite or a backdrop in the "Backdrops" tab of the stage. Common base for SRVectorCostume and SRBitmapCostume.
- type:
str - description: The name of the costume. Must be unique for each costume in a sprite.
- type:
str - description: The extension of the costume if saved as a file. Usually
"svg"(SRVectorCostume) orpng(SRBitmapCostume).
- type:
tupleofint|float(x position) andint|float(y position) - description: The coordinate the costume is centered at i.e. will be rotated around as a vector from the top left.
- note: exists on both possible subclasses just with a different type.
Represents a costume in "Vector" mode in the "Costumes" tab of a sprite or a backdrop in the "Backdrops" tab of the stage. It is based on an SVG image.
- type:
_Element(from packagelxml.etree) - description: The actual SVG image basis of the costume as an XML element tree.
SRVectorCostume(
name="Abby-a",
file_extension="svg",
rotation_center=(31, 100),
content=<Element {http://www.w3.org/2000/svg}svg at 0x781e6c4200>,
)- Yes I know. lxml Elements have a terrible
__repr__:(.
Represents a costume in "Bitmap" mode in the "Costumes" tab of a sprite or a backdrop in the "Backdrops" tab of the stage. It is based on an bitmap image (e.g. a PNG).
- type:
Image(from packagePIL.Image) - description: The actual bitmap image basis of the costume as created by pillow's
Image.open. PenguinMod seems to limit and reduce image size to(480, 360)when importing from a file.
- type:
bool - description: Pretty useless. Seems to always be
True. PenguinMod seems to limit and reduce image size to(480, 360)when importing from a file.
SRBitmapCostume(
name="costume1",
file_extension="png",
rotation_center=(88, 72),
has_double_resolution=True,
content=<PIL.PngImagePlugin.PngImageFile image mode=P size=176x144 at 0x781e6b60c0>,
)Represents a sound in the "Sounds" tab of a sprite or the stage.
- type:
str - description: The name of the sound. Must be unique for each sound in a sprite.
- type:
str - description: The extension of the sound if saved as a file. Usually
"wav"or"mp3".
- type:
AudioSegment(from packagepydub_ng) - description: The actual audio segment basis of the sound as created by pydub_ng's
AudioSegment.from_file.
SRSound(
name="Squawk",
file_extension="wav",
content=<pydub.audio_segment.AudioSegment object at 0x781e6bce90>,
)- For a documentation overview and all pages of the tutorial, see docs/index.md
- For an instruction on Getting info on opcodes(this is further ahead in the tutorial), see docs/doc_api.md
- Next Page: Analyzing and Editing Projects, see docs/analyze_edit.md





















