Beckett - Phase 2 Report

Over the past three months, we’ve completed phase two of the Beckett project by prototyping a collaboration plugin for the Godot game engine. The plugin supports both live collaboration and working in parallel asynchronously. Collaborators can branch off to work in private, view a visual diff of their changes and merge them back to the main version. We believe these core primitives can support many workflows, including classroom instruction and longer-term collaborations. In this report, we briefly summarize what we’ve built, what we’ve learned so far, and what comes next.

Recap: project goals

This project originated by hearing about the challenges that the Endless Foundation was facing teaching version control concepts in the classroom. Git is a hurdle for early learners—the command line and text diffs are confusing to use, and the versioning tools aren’t integrated with the editor.

We set out to design a version control experience that:

We structured the project in three phases:

We’ve now completed phase two and are moving on to phase three.

The Beckett Prototype

We’ve created a collaboration plugin, which runs on top of a forked version of the Godot editor. In the plugin, you can:

With this set of capabilities a classroom group can experiment with variations of a lesson, a mentor can “visit” the branches and offer help or feedback, and the work can be landed back on the main project.

Here’s a demo video showing those features:



Technical Implementation

We’ve had to overcome a variety of technical hurdles to create this collaboration experience within the Godot engine, since Godot was not designed with real-time collaboration in mind. Much of the work of this phase has gone into creating an implementation that’s robust and reliable enough that we think it can hold up to testing by students on real projects.

We now have a solid core to build on: a representation of a Godot project in Automerge, support for all the various property pickers, code, and media required to actually work on a project, and some initial user interfaces for working with branches and history.

Findings so far & possible future work

We expect to learn a lot from this prototype in testing with students in Phase 3. But we have already learned some things about the design and implementation of our system by building many prototypes and testing them with Justin and members of the Endless team.

Things that worked

Our limited initial testing suggests that this prototype has a lot of potential to improve collaboration in Godot. Here are a few highlights of positive moments:

It’s fun to play each other’s games. When you’re on a remote game jam, it feels great to be able to instantly try out a game that someone else developed, and then further remix their game and have them try out your version.

It’s useful to see diffs of nonvisual properties. In Godot, it’s quite easy to accidentally make changes to the game without realizing what you’re doing. In our plugin, you can easily see all the properties that have changed on an object from within the editor, which makes it easier to notice and fix these kinds of accidents. (We had some examples where one user spotted another user’s error by looking at a diff.)

Live synchronous collaboration on a branch is a fun way to teach/learn Justin was able to teach Geoffrey about bounding boxes on platforms. They took turns modifying the same branch and were able to explore together while on a live call.

Challenges

Building our project as a plugin to the Godot editor has the huge benefit of building on existing workflows and lesson plans, but it also means there are some limits to what we can easily build. Here are some challenges we discovered while trying to implement collaboration workflows within the engine, which could be a lot of work to solve.

Per-keystroke “live” collaboration is tricky to implement Our current collaboration system is lively: changes from other users are displayed as soon as they arrive. However, we only record and send those changes each time a collaborator manually chooses to save the project. There are design challenges around live collaboration, but the main obstacle is technical. The Godot engine doesn’t expect to receive live changes and so reloading resources can be an expensive operation that blocks user input while it runs.

History views could be valuable, but are difficult to implement in Godot. The ability to travel back and view earlier versions of a project can be a useful way of understanding past work. In our Patchwork editor, we support “time traveling” to previous versions of any document. Unfortunately, we haven’t yet added this feature in Beckett. When viewing earlier states of a document, it’s important that the editor enters a read-only mode to prevent making changes. Godot doesn’t yet support read-only mode, and adding it to this prototype would be a significant undertaking.

Live “presence” would be helpful for instructors. When collaborating on a screen share, the person sharing their screen can use their cursor to point at a panel or indicate some part of the project they’re discussing. Some collaborative tools like Figma allow for multiple cursors, or to “follow” a presenter around the document. Observing live sessions with only a single participant sharing their screen highlighted how valuable it would be to allow everyone in a collaboration – both mentor and learner – to be able to navigate and point at elements of the project. It would be possible to add this to Beckett, but again, would require significant engineering effort.

Notes on visualizing changes

It’s important that users can see what has changed so they can reason about their work and understand what other people have done. Showing the user what has changed is also the prerequisite for more sophisticated workflows like reviewing and commenting on changes or cherry picking changes from one branch to another.

We found that there is a need for seeing at a high level what has changed overall to get a quick impression. But it’s also important that users can see all changes in detail to make sure they are not missing subtle changes that are non visual. We’ve built two tools to serve these two usecases:

Games are often very colorful. Adding an overlay to highlight changed or added regions can easily get lost. Instead what we have found to be more useful if the whole scene is grayed out except for the regions that have changed:

the highlights on the right stand out more because the rest of the scene is grayed out

There are some kinds of changes where we’d like to further improve the diff visualizations. In our current prototype, we visualize nodes that have moved position by showing the before-after coordinates in the sidebar. As expected, this is not a very useful way to see what’s moved. The highlight in the scene also only works on the node level. Some nodes like a tilemap have a more granualar structure. Ideally you would like to see specifically which parts of the tilemap has changed. This would require more feature specific code.

Indie dev workflows

In addition to working with Justin & Will (and the rest of the Learning team) we also spent time exploring how to make these tools serviceable for the broader community. In our interviews, we found the following:

Overall, we think many of these issues could be addressed by our approach. By making it possible to merge changes within files in many more situations, we can allow developers to collaborate more ambitiously. Integrating tools into the IDE could also allow artists and developers to collaborate more freely (provided the engine’s own native tooling is legible to an artist.) Finally, there are interesting cultural opportunities for us to learn from: locking files is not just a technical mechanism but provides coordination. No merge algorithm can realistically prevent all conflict, and so we should consider how we can serve the coordination needs of a team when conflict is inevitable.

Next steps

Now, we aim to work with Justin & Will to develop some lesson plans based on Moddable Platformer to test this work with students, and to use their input to iterate on the user interface. In phase 3 we’ll also do some further refinement and fix bugs, but we won’t plan to add any new features.

Some questions we plan to explore in Phase 3:

What are existing barriers in the teaching process which are helped by this prototype? For example, we (together with the Endless learning team) have a hunch that mentors will have an easier time identifying students who need help in a remote classroom setting if they’re able to inspect student work live.

What kinds of new workflows / lessons are enabled by this collaboration tooling, that weren’t possible before? For example, live synchronous collaboration might enable new teaching and mentoring patterns in a remote setting. We’ve had some discussions with Justin about this potential.

How do these collaboration primitives apply in different contexts? In-person vs remote classes, live lessons vs asynchronous self-serve experiences, and small classrooms vs large collaborations are all dimensions of variation to explore. Although we hope that our work is beneficial in all these contexts, it’ll apply in different ways.

How much complexity should we allow in the branching model? We could present students with a very constrained model where they can only fork off from main, or we could allow arbitrarily branching off of branches. We could prevent merging changes back, or allow it always, or only in some cases. Which combinations balance simplicity and power?

How many guardrails do students need? Right now we have a very open model where anyone can make changes on any other branches. We could add some simple guardrails—e.g., users can only change their own branch. Another approach: instead of trying to prevent students from making mistakes, we could be very permissive but make it very easy to recover from it by going back to a previous version that worked.

How much should we lean into version control terminology? Branches, forking and merging are new technical terms from version control that students are not familiar with. The question is if it’s a good idea to expose learners to this vocabulary so they can map our concepts more easily to other version control systems like Git, or should we use a more familiar vocabulary like remixing or modding.

Technical todos

During Phase 2 of the project we had to find the right balance between making the implementation more solid and expanding the capabilities we have. Phase 3 will involve some amount of engineering work to fix bugs and refine the features we have in response to testing it with users.

We have a short term list of things we need to fix. Beyond that there is a more long term perspective of what would be needed to turn Patchwork into a proper plugin that can be used by the broader Godot community.

Open issues

To improve:

Nice to have

Publishing Patchwork as a Godot plugin

For implementing Patchwork we had to fork Godot so we can get access to some internal APIs. This is good enough to run some trials with some students but long term we want to turn Patchwork into a real plugin that works with regular Godot. For that we would need to land some pull requests to add the APIs we need.

API for inspecting/saving the Script editor state

In order to maintain consistent state when syncing to patchwork or performing a code versioning action (like checking out, merging, etc.), we need to check whether or not resources currently open in the editor are edited but unsaved, and be able to save the unsaved resources. While Godot currently exposes this functionality for the scene editor, it does not expose it for the script editor.

API for detecting if the editor file system is currently importing

We do not want to start syncing the project to patchwork if the editor is currently importing resources (e.g. the user just dropped file(s) into the project and Godot is now importing them). This can lead to large slowdowns in usage, and possible inconsistent state and crashes. Godot currently does not expose the EditorFileSystem::is_importing() function, which we are using to prevent syncing during import.

API to use inspector properties

Godot currently doesn’t expose any of the EditorInspector functionality (i.e. the graphical way of viewing properties in the “Inspector” tab) to external scripts. This is the current way we are exposing the graphical “Diff” view in the patchwork tab.

API for retrieving resource importer

For producing graphical diffs of the various dependent resources that scenes depend on (like textures), we need to re-import previous versions of resources. While Godot does expose functionality for re-importing files into the project tree, this modifies the project state, which we want to avoid. We currently re-import previous versions of importable resources outside of the project tree by retrieving the appropriate importer object for the resource by calling ResourceFormatImporter::get_importer_by_name. This is currently not exposed in the Godot API.

Future explorations

In this initial project we’ve developed primitives like branches, visual diffs and merge previews—but each of these aspects warants an exploration on their own. Further projects on this foundation would allow us to go a lot further:

Giving feedback

Branches are useful to work in parallel but they are also a useful to group a set of changes that users can share with others to get feedback on and discuss the changes.

Avoiding conflicts

Merge conflicts are complicated to resolve, so ideally we want to avoid them when possible. Games have the additional challenge that some asset types like 3D models or textures don’t have a way to easily combine changes from different versions. A popular mechanism in games to solve this is file locking so only one user can edit a file at a time.

Working with changes

Remix playground - students can mod a base game and split up their changes into meaningful change groups so aspects from different students can be combined to create new games

History

How do you visualize what’s happened on a game? eg, nice views of the change log, manually editing the changelog grouping; viewing history over multiple documents together. This is a deep area of exploration and it’s closely related to everything above, but we just don’t think we’ll have time to explore in depth.

Embedding Godot in Patchwork

In the long run we don’t want Godot to be just an isolated app. Building an integration for Godot should allow us to pull it into our web platform so we can use the existing Patchwok tools in Godot projects as well. Some example use cases this could enable:

Versioning design document + code together: - If both the Godot project and the design document lived in patchwork both could be versioned together. A new feature could make a change both to the design document and the project to implement it. Stats of entities from the desing document could be also referenced directly from the game instead of copying over these values manually.

Interactive tutorials: - Instructors could create a markdown document that walks students through how to mod a game in Godot in Patchwork. The document could embed a live running version of the game and parts of the godot editor like an individual property editor or an editable code snippet which they can use to mod the game from within the document. That way the user can gradually learn the individual concepts in the flow of the tutorial with out being overwhelmed

Share and mod games on the web - We could allow students to easily share a link to their games that anyone can play directly on the web without installation. Beyond just playing these games in the browser, we could also load the complete Godot Editor, enabling players to seamlessly transition from playing to modding with a single click. This could even allow them to create pull requests to contribute improvements back to the original games.