Skip to content
Development
Skill

/web-export

Use when shipping a Godot game to the browser — Web export preset options, threads vs no-threads and COOP/COEP headers, hosting on itch.io or your own server, PWA, JavaScriptBridge, user:// persistence, audio and input limits, and load size

BOOST
From plugin
godot-prompter
86261 skills9 agents1 hook
Install
$ npx -y skills add jame581/GodotPrompter --skill web-export --agent claude-code

How it fires

How this skill gets triggered: by you, by Claude, or both.

  • Fires itselfAuto-invocation. Claude auto-loads it when your prompt matches the work.Auto-invocation is when the right skill fires by itself at the right moment, driven by a FLOW.md router and a hook, instead of you invoking it by name. It is the difference between a skill being installed and a skill actually getting used.Read the full definition →
  • You can call itInvoke it directly when you want it.
  • Slash command/web-export

Context preview

The summary Claude sees to decide when to auto-load this skill.

Use when shipping a Godot game to the browser — Web export preset options, threads vs no-threads and COOP/COEP headers, hosting on itch.io or your own server, PWA, JavaScriptBridge, user:// persistence, audio and input limits, and load size

SKILL.md

web-export.SKILL.md
name: web-export
description: Use when shipping a Godot game to the browser — Web export preset options, threads vs no-threads and COOP/COEP headers, hosting on itch.io or your own server, PWA, JavaScriptBridge, user:// persistence, audio and input limits, and load size

Web Export in Godot 4.3+

Ship a Godot 4.x game as HTML5/WebAssembly. This covers what is different from a desktop export: the renderer, threading and server headers, browser interop, persistence, and the input and audio rules browsers enforce. All examples target Godot 4.3+ with no deprecated APIs.

**C# projects cannot export to Web in Godot 4** — the .NET editor refuses the export (still true in 4.7.2). The code in this skill is GDScript only for that reason; a C# game that needs a browser build must be ported to GDScript or stay on Godot 3.

> **Related skills:** **export-pipeline** for presets, CLI export and CI/CD, **web-services** for HTTP and WebSockets from the browser, **rendering-pipeline** for what the Compatibility renderer can and cannot do, **audio-system** for buses and playback, **save-load** for save formats.

---

1. What Changes on Web

| Area | On Web | |---|---| | Renderer | Always **Compatibility** (WebGL 2) — `rendering/renderer/rendering_method.web` defaults to `gl_compatibility`. No SDFGI, VoxelGI, volumetric fog, SSR, FSR, or screen-space AA | | Scripting | GDScript and GDExtension only. No C# | | Threads | Optional. Off by default; turning them on needs special server headers (Section 3) | | Audio | Sample playback through the Web Audio API by default — `AudioEffect`s on buses do not apply (Section 6) | | Files | `user://` lives in the browser's IndexedDB; there is no access to the player's disk except downloads and file-picker uploads | | Networking | HTTP via the browser's `fetch` (CORS applies), WebSockets and WebRTC only — no raw TCP/UDP, so no ENet | | Processes | No `OS.execute()`, `OS.create_process()`, or quitting the tab |

Design for this from the start if web is a primary target. Porting a Forward+ game late means re-lighting it.

---

2. The Export Preset

Add a **Web** preset in **Project → Export** (export templates must be installed). The options that matter:

| Option | Default | Set it when | |---|---|---| | `variant/thread_support` | `false` | You need threads and can serve COOP/COEP headers (Section 3) | | `variant/extensions_support` | `false` | The project uses GDExtension (needs the extension's web build) | | `vram_texture_compression/for_desktop` | `true` | S3TC/BPTC textures for desktop browsers | | `vram_texture_compression/for_mobile` | `false` | Turn on for phone browsers (ETC2/ASTC); costs a second texture set in the PCK | | `html/canvas_resize_policy` | Adaptive | `None` / `Project` when embedding in a fixed-size page element | | `html/focus_canvas_on_start` | `true` | Keep on so keyboard input works without a first click | | `html/experimental_virtual_keyboard` | `false` | Mobile browsers need an on-screen keyboard for `LineEdit` | | `html/head_include` | empty | Extra `<head>` tags — analytics, meta tags, fonts | | `html/custom_html_shell` | empty | Replace the whole loading page with your own template | | `progressive_web_app/enabled` | `false` | Installable, offline-capable build (Section 4) | | `threads/emscripten_pool_size`, `threads/godot_pool_size` (Godot 4.5+) | 8, 4 | Only shown with thread support; lower them to reduce memory |

The output is an `.html` page plus `.js`, `.wasm`, `.pck`, and audio worklet files — upload all of them together. The default filename for the page should be `index.html` for most hosts.

CLI export works as on desktop: `godot --headless --export-release "Web" build/web/index.html`.

---

3. Threads or No Threads

Threaded builds use `SharedArrayBuffer`, which browsers only enable on a **cross-origin isolated** page. The server must send both headers on every file of the export (the page, its scripts, and the worker scripts):

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

| | No threads (default, Godot 4.3+) | Threads | |---|---|---| | Hosting | Any static host | Needs the two headers above, or the PWA workaround | | Audio | Sample playback, low latency | Sample playback by default; stream mode crackles more | | Embeds, ads, third-party iframes | Work | Break unless they also send CORP/CORS headers (`require-corp` blocks them) | | `WorkerThreadPool` | Tasks run inline on the main thread, so heavy work stalls frames | Real background threads | | `Thread` | **`start()` returns `OK` but the function never runs** | Real background threads | | Feature tag | `nothreads` | `threads` |

**Default to no threads.** Turn them on only when profiling shows a real need (heavy procedural generation, physics on background threads), and you control the server or use a host that sets the headers. Code that must behave differently can check `OS.has_feature("threads")` — and any `Thread`-based code (level generation, loaders) **must**, or it silently does nothing on the default build. `WorkerThreadPool` is the portable choice.

Godot's own **Remote Debug → Run in Browser** server sends the headers, so a threaded build can work locally and fail once uploaded. Test on the real host.

---

4. Hosting

| Host | What to do | |---|---| | **itch.io** | Upload a ZIP with `index.html` at its root, set the project kind to HTML. For threaded builds tick **SharedArrayBuffer support** in the embed options | | **GitHub Pages, plain static hosts** | No custom headers: ship the no-threads build, or enable PWA with `progressive_web_app/ensure_cross_origin_isolation_headers` (default `true`) so a service worker adds the headers after the first load | | **Your own server / CDN** | Send COOP/COEP for threads, serve `.wasm` as `application/wasm`, and precompress `.wasm` and `.pck` with Brotli or gzip |

Server config snippets (nginx, Apache, Netlify, Cloudflare Pages), compression, and cache headers: [r

Read more
Ships withgodot-prompter

Agentic skills framework for Godot 4.x game development. Gives AI coding agents domain-specific expertise for GDScript and C# projects.

Get the whole plugin

Other skills on godot-prompter.