OpenArthurian: Day 18 of the New Age of Arthurian

Builds are finally working, at least for MacOS (Will need to test on Windows once I get home)

After many, many iterations under polished rules, I think the way it wound up working was running a node process externally who did the actual packaging since using the same node that was running the packaged Studio became just too much of an issue. So I wonder what requirements will the developers have (will they need to have nodejs installed in their machines? likely.)

Here’s gemini’s brief on what we ended up with:


To implement a reliable and robust Build support in Arthurian Studio, I moved through several architectural iterations to solve environment-specific communication and stability issues. 

The final implementation follows this architecture:

1. Project Assembly & Staging

The studio first gathers all necessary components into a temporary “staging” directory:

  • Runtime Source: Copies the selected game engine runtime (e.g., oax6-nightly)
  • Scenario Data: Synchronizes the project’s JSON data and maps.
  • Assets: Copies game resources (images, sounds).
  • Electron Wrapper: Dynamically generates a package.json and a minimal main.js to turn the web-based game into a standalone desktop application.

  2. Isolated Build Utility

 To prevent the packaging process from blocking or crashing the main Studio application (which caused the “reply was never sent” errors), I implemented an isolated build process:

  • Dynamic Script Generation: The Studio writes a temporary Node.js utility script on the fly.
  • System Node Execution: This script is executed using the system’s standard node binary rather than the internal Electron binary. This provides a more stable environment for heavy disk I/O and child-process management.
  • @electron/packager API: The utility uses the JavaScript API of @electron/packager to handle the platform-specific heavy lifting (downloading Electron binaries, creating the .app or .exe, and creating the ASAR archive).

  3. Filesystem-Based IPC (The “Status File”)

Because standard process pipes (stdout/stderr) proved unreliable for real-time status updates in this environment, I implemented a Filesystem-based Inter-Process Communication:

  • Status JSON: The build utility writes its current state (started, success, or error) and the final artifactPath to a hidden JSON file in the temp directory.
  • Heartbeat Polling: The main Studio process polls this file every 2 seconds to update the UI status (“Starting build…”, “Packaging…”, etc.).
  • Log Preservation: A dedicated .log file is maintained during the build. If a build fails, the Studio reads this log to present the exact error to the user.

  4. Robust Completion Detection

  The system now uses a three-tier verification to ensure the build is truly finished:

  1. Direct API Signal: The utility script reports success via the status file.
  2. Path Verification: The Studio verifies the reported artifact path actually exists on disk.
  3. Fallback Scan: If the signal is lost but the process exits successfully, the Studio performs a “smart scan” of the output directory (handling sanitized project names and ignoring system junk like .DS_Store) to find the result.

  5. Lifecycle Safety

  • Timeouts: A 10-minute safety timeout ensures the Studio doesn’t stay “stuck” if the external process hangs.
  • Cleanup: Temporary utility scripts are deleted immediately after the process closes, and staging directories are cleared only after a confirmed successful build.

This multi-layered approach ensures that even on slow filesystems or in restrictive environments, the build process is stable, observable, and always reports its final outcome correctly.


In any case I don’t feel in a rush to improve the developer experience on this aspect for now; there are more pressing things to make this tool useful (and I’m running out of time to work on it)

Ended up the journey by further polishing the generated builds so that the program exists when the main window is closed (which, for some reason, mac apps most of the times don’t do by default), and making sure the test project is bundled within the executable for people to play around with it.

Leave a comment