dragonruby-rack

Serve a DragonRuby GTK HTML5 export from a Rack or Rails app, on your own domain, without an iframe and without itch.io.

# Gemfile
gem "dragonruby-rack"

# config/routes.rb
mount DragonRuby::Rack::Game.new(Rails.root.join("games/underwater")) => "/underwater"

That is the whole thing. The game is then at /underwater/.

Built for and running on stammer.dev/underwater.

Why this is not just a static directory

DragonRuby's WASM runtime allocates a SharedArrayBuffer, and browsers hand that out only to a cross-origin isolated document — one served with both

Cross-Origin-Opener-Policy: same-origin
Cross-Origin-Embedder-Policy: require-corp

Rails' static file server runs before the router and cannot set headers per path, so a bundle dropped into public/ is served without them and the game never boots. Hence: keep the bundle outside public/, serve it through this endpoint, which sets the headers on the document and on every subresourcerequire-corp applies to the .wasm too.

The second thing it does is less obvious. The export links its assets relatively (game.css, gamedata/…), which under a mount only resolve if the document URL ends in a slash — and nothing can guarantee that, since Rails normalizes the path away before the endpoint sees it and a redirect onto the slash would be a loop. So the endpoint injects a <base href="/underwater/"> into the served HTML, and the assets resolve either way.

Without Rails

It is a plain Rack app; Rails is not a dependency.

# config.ru
require "dragonruby-rack"
run DragonRuby::Rack::Game.new("builds/underwater-html5")

or mounted:

require "dragonruby-rack"

app = Rack::Builder.new do
  map("/underwater") { run DragonRuby::Rack::Game.new("builds/underwater-html5") }
end

Getting a bundle in

Export the game (dragonruby-publish --platforms=html5 --package …) and unpack the zip where the mount points:

rake dragonruby:install[../underwater/builds/underwater-html5.zip,underwater]

The task replaces the directory rather than unpacking over it — a file that existed in the old version and not in the new one would otherwise stay behind and be served for good. Because that is a delete, it refuses any destination that is not empty and holds no index.html, and it checks afterwards that what came out has an index.html and a .wasm in it (a desktop export unzips perfectly well and then serves nothing). FORCE=1 overrides the refusal.

config.dragonruby.games_root sets where bundles live; the default is games.

Generator

rails g dragonruby:mount underwater

Creates games/underwater/ and writes the mount into config/routes.rb. --path= and --at= override the directory and the URL. Running it twice does not mount the path twice.

What this gem is not

It does not contain DragonRuby, and it does not build your game. DragonRuby is commercial software with its own licence; you need your own copy to produce the export this serves. This gem only takes the finished directory and puts it on the web correctly.

Development

bundle install
bundle exec rspec

Licence

MIT. See LICENSE.txt.