Google Chrome Labs keeps an Awesome HTML-in-Canvas list of demos for the API, and one of them is a Godot scene of mine.

Here’s how the Godot side works. The three panels in the scene are real HTML, drawn straight into textures Godot already owns. You can select text on a tilted panel while the camera moves, Ctrl+C it, Ctrl+F finds it, right-click translate works. (It’s real DOM, so it’s also in the accessibility tree, which a canvas HUD normally isn’t.)

The bit that’s useful even if you never touch this API is getting at Godot’s own WebGLTexture from GDScript:

  • RenderingServer.texture_get_native_handle(tex.get_rid()) gives you the GL texture id (web export = Compatibility renderer)
  • inside JavaScriptBridge.eval, GL.textures[id] is the actual WebGLTexture (emscripten’s lookup table)
  • write to it from JS, then put the GL state back after (active texture, binding, unpack flags). Godot doesn’t expect anyone else touching its context

Chrome changed the API this week: texElementImage2D became texElementSubImage2D, panels need a new drawable attribute, and hit testing moved to updateElementGeometry. For a Godot texture the new version fits better actually, Godot already allocated the storage so it’s just a sub-image write. I kept the old path behind feature detection since stable Chrome is still mid-transition.

Caveats up front: Chromium only (origin trial on the demo, or the CanvasDrawElement flag). Mozilla and WebKit haven’t taken a position yet, both requests are still open. So it’s an experiment, not something to ship a game on.

Source (MIT): https://github.com/Vav-Labs/quest-signal Write-up + live demo: https://vav-labs.com/case-studies/quest-signal/

  • Pulling Godot’s own WebGLTexture through texture_get_native_handle + GL.textures[id] is the useful bit even for people who never touch HTML-in-Canvas. Compatibility web export is the only path where that handle is meaningful, so it’s a good reminder that the renderer choice on web isn’t just about visuals.

    Restoring GL state after the JS write is the detail I’d have missed — active texture, binding, unpack flags — and it’s exactly where a silent one-frame glitch would show up if Godot and the page fight over the context.

    Agree this stays an experiment until Mozilla/WebKit move. Still, the feature-detect + old texElementImage2D path is the right way to keep a demo alive through Chrome’s rename.