Skip to content

Achieving full Scratch support #12

@cbcode1

Description

@cbcode1

One of the more ambitious goals for this widget is to provide full support for Scratch, as it is the most popular block-based programming language. This means that the widget should be able to handle all Scratch blocks and provide options to import and export Scratch projects.

After investigating multiple approaches to achieve this goal, these are my findings:

Approach 1: Extend the current widget

The "naive" approach is to use everything the current widget offers and extend it to support Scratch. This would mean adding all the missing blocks, as well as the ability to import and export Scratch projects.

While this approach is probably the cleanest and the most straightforward, it would require a lot of work: More than 100 additional blocks (yes, I counted them) would need to be added, as well as support for things such as multiple stages, sprites, costumes, sounds, custom blocks, and so on. To avoid unexpected behavior, all blocks (including existing ones) would need to behave exactly as they do in Scratch. Additionally, the import and export functionality would need to be implemented to convert between the widget's internal representation and Scratch's .sb3 file format.

Of course we could settle for ~90% Scratch support, but that would still require a lot of work, and not all Scratch projects would be supported. This approach is also not very future-proof because every new Scratch block would need to be added manually.

One advantage of this approach is that it would keep the widget flexible to support other block-based programming languages in the future because it does not depend on any specific libraries. It would also allow us to keep the widget's codebase clean and minimal, as we would not need to integrate additional libraries.

Overall, I do not recommend this approach.

Approach 2: Use the existing Scratch libraries

Since Scratch is an open-source project, we can use the libraries that the Scratch Foundation provides on GitHub for our widget. Most notably, these include scratch-blocks, scratch-vm and scratch-render.

Unfortunately, these libraries are very poorly documented, as the only one intended use case is the official Scratch editor. They also do not use TypeScript, which makes using them even more difficult. However, the Scratch editor is an open-source React application (scratch-gui), so we can look at how it uses these libraries to figure out how to use them ourselves. The React project is huge and complex, but I could not find another project that uses these libraries.

As far as I can tell, the scratch-blocks library is a fork of Blockly and could replace Blockly in the current widget. The major difference from Blockly is that it is designed to be used with the Scratch VM rather than translating blocks to JavaScript. It provides all the blocks that Scratch supports. The scratch-vm library provides the virtual machine that executes the blocks. The scratch-render library provides the rendering engine that could replace PixiJS in the current widget. How the libraries can be linked together can be seen in the scratch-gui project, which is the official Scratch editor.

Some smaller libraries we might need are scratch-storage for asset and project file management, scratch-audio for audio playback, and scratch-svg-renderer for rendering SVGs. These libraries are also used in the scratch-gui project.

We would need to figure out how to adapt the libraries to save the project in the widget's properties.

Using only the necessary Scratch libraries would allow us to easily support all Scratch blocks while keeping the widget's codebase clean and minimal. This approach would also allow us to keep parts of the existing widget's code and its Shoelace-based UI, which fits well with WebWriter. Additional UI elements that could take up space, such as the import and export buttons, could also be placed in WebWriter's options pane.

Since some Scratch libraries are AGPL-3.0 licensed, we may need to change the widget's license, but I do not think that this will be a problem.

I believe that this is the best approach to achieve full Scratch support in the widget. However, it would still require a lot of work to integrate the libraries. The scratch-gui project is a good reference for how to do this, but it is a complex project that would need to be simplified for our use case.

Approach 3: Slim down the existing scratch-gui React project

The third approach I considered is to fork the existing scratch-gui React project and slim it down to include only the necessary parts for our widget. This would mean removing all the unnecessary features, such as the top navigation bar, the SVG editor, the sound editor, and the asset library. I noticed that even the April Fools' jokes from past years are still in the codebase, so there is a lot of unnecessary code that could be removed.

Slimming down the existing editor would be easier than integrating the libraries ourselves. This would also mean that we keep the existing Scratch UI, which is familiar to many users, though it would not fit WebWriter's UI style. The final React component could then be wrapped inside a web component to be used as a widget. This is obviously not really pretty and would require synchronizing the widget's properties with the React component's state, but this is not too difficult to do.

However, there are some downsides to this approach. Since WebWriter widgets are not always used in full-screen mode, the Scratch GUI would need to be modified for smaller spaces, which is not currently the case (and a fullscreen button would need to be added to the editor). The React project is also huge and depends on many other libraries. While its performance is good in the official Scratch editor, embedding it in a larger document (with possibly multiple instances of the widget) could lead to performance issues. As with the previous approach, we would also need to synchronize the widget's properties with the Scratch project's state. Additionally, we should move some of the Scratch editor's UI elements to WebWriter's options pane, such as the import and export buttons.

Overall, I think that this approach might be the easiest to implement, but I am not sure whether the result would be satisfactory for WebWriter's users. It could also happen that slimming down the existing editor will be more work than integrating the libraries ourselves, which would make this approach not worth it.

Conclusion

Achieving full Scratch support in the widget is a significant task and will require a lot of work, regardless of the chosen approach.

I believe that the second approach, using the existing Scratch libraries, is theoretically the best one, as it allows us to keep the widget's codebase clean and minimal while still providing full Scratch support. However, if integrating the libraries turns out to be more difficult than expected, approach three is probably the safer choice. The first approach would require the most work by far, but it would keep the widget flexible enough to support other block-based programming languages.

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions