For three.js developers

three.js games on Steam, and how to ship yours as a desktop app

Steam sells desktop apps, not web pages. Here is how a three.js game becomes one, which wrapper to pick, how Steam features get wired in, and what shipping a browser inside your game costs.

The short answer

A three.js game reaches Steam inside a desktop wrapper. Electron and NW.js bundle their own Chromium and Node.js, while Tauri uses the webview already on the system. Steam features such as achievements, cloud saves and the overlay come through a Node binding like steamworks.js. Steam needs a store page, a Steam Direct fee per game and an uploaded build with an executable, and Windows is where most Steam players are. It has been done at scale. CrossCode shipped on Steam as an HTML5 game running in NW.js, and Vampire Survivors reached its 1.0 release on Steam while still built on the JavaScript framework Phaser.

A three.js game already runs on every desktop that has a browser. Steam does not take a URL, though. Every build you upload is a set of files in a depot, with a launch option that points at an executable, such as Game.exe on Windows or Game.app on macOS. So the job is to turn your web page into that executable, add the Steam features players expect, and make sure it still runs well outside a browser tab.

There are three mainstream wrappers, one Steam binding most JavaScript games reach for today, and a handful of performance traps that tend to show up after release rather than before it. This guide walks through each with the settings that matter, looks at two games that shipped this way, and covers the other route. If the game has outgrown three.js, a native build from a game engine avoids the wrapper entirely.

What it does

Electron

Embeds Chromium and Node.js into its own binary. You get one known browser version on every player's machine, which makes WebGL behavior predictable, at the cost of the largest download of the three options.

NW.js

An app runtime based on Chromium and Node.js, formerly called node-webkit, that lets page code call Node modules directly. CrossCode runs on it. The trade-offs are close to Electron's.

Tauri

Uses the webview already on the system instead of bundling a browser, so a minimal app can be under 600 KB. The catch for a WebGL game is three rendering engines to test, WebView2 (based on Chromium) on Windows, WKWebView on macOS and webkit2gtk on Linux.

steamworks.js

A modern Steamworks SDK implementation for HTML, JavaScript and Node applications, MIT licensed, with Electron and NW.js support. It covers achievements, the local player, cloud saves and the Workshop, and has a helper that enables the Steam overlay in Electron.

Greenworks

The older binding, built by Greenheart Games for Game Dev Tycoon and usable from NW.js and Electron. Its maintainers now describe it as best-effort maintenance, so new projects usually start with steamworks.js.

A native build instead

A game engine produces a real executable with no browser inside. Summer builds Windows and macOS versions of a Godot 4 compatible project for Steam once the export templates are installed. That means rebuilding the game in the engine, not wrapping it.

How it works

  1. 1

    Step 1: Make the web build run from local files

    Bundle every script, model, texture and sound into the build folder with relative paths and no CDN calls at startup. Players expect a Steam game to launch offline. Electron's security checklist also says code with Node access should only ever come from local packaged files, never remote pages.

  2. 2

    Step 2: Pick a wrapper and open the window

    For most three.js games Electron is the safest start because every player gets the same Chromium. Create a fullscreen or resizable window that loads your local index.html. Decide what happens when the window loses focus. Electron's backgroundThrottling defaults to true and throttles animations and timers in the background, so pause the game on blur yourself, or set it to false if music or a simulation must keep running.

  3. 3

    Step 3: Add Steam with steamworks.js

    Initialize with your app ID, then call achievements and cloud saves from the renderer. Call electronEnableSteamOverlay() at the end of main.js to get the overlay. The README's Electron setup turns on nodeIntegration and turns off contextIsolation, which Electron's security checklist advises against, so load only your packaged local files in that window and never a remote URL.

  4. 4

    Step 4: Package a Windows build and upload it

    Package with the wrapper's tooling, then copy the Steam redistributable files from the Steamworks SDK into the build root, as the steamworks.js README describes. Upload the folder as a depot with SteamPipe and set a launch option that points at your .exe. Add a macOS depot later if you want one.

  5. 5

    Step 5: Open the store page early

    Pay the Steam Direct fee of 100 US dollars per game, which Valve pays back after the game earns 1,000 US dollars in adjusted gross revenue. The store page must be visible as Coming Soon for at least two weeks before release. Valve's build review typically takes 3 to 5 business days, and Valve asks you to plan for at least 7.

  6. 6

    Step 6: Test on weak hardware for an hour

    Run the packaged build, not the dev server, on an integrated-graphics laptop. Watch frame pacing, memory use over a long session, the overlay with Shift+Tab, and alt-tab behavior. Wrapper bugs tend to appear after release, when thousands of machines run the game for hours.

Two ways to run it

In Studio, or from the agent you already use

In Summer Studio

Summer Studio runs in the browser and makes the assets a Steam release needs. Generate capsule art for the store page, 3D models as GLB files your three.js scene can load, sound effects and music. Every result is a file you download and use in any engine. Studio does not wrap or package games for Steam.

Open Summer Studio

From Claude, Cursor or Codex via MCP

If the three.js game has outgrown the wrapper and you want a native build, the Summer MCP lets Claude Code, Cursor or Codex rebuild it in the Summer desktop app. The agent imports your GLB files, writes GDScript from your JavaScript as the spec, and runs the game to check each system. Summer then builds Windows and macOS versions for Steam.

Example prompt for your agent

Use src/game.js and src/player.js from my three.js project as the spec. In the open Summer project, import the models from assets/models, rebuild the player controller and the first level, run the game with summer_play and send me a screenshot of the first room.
Set up the Summer MCP
Wrappers for a three.js game on Steam
WrapperBrowser engineSteam bindingBest when
ElectronIts own bundled Chromiumsteamworks.js, including an overlay helperYou want the same rendering on every machine and can accept a large download
NW.jsIts own bundled Chromiumsteamworks.js or GreenworksYou want Node modules callable straight from page code
TauriSystem webview, WebView2 on Windows, WKWebView on macOS, webkit2gtk on LinuxNo Node runtime, so Steam calls go through the Rust side of the appDownload size matters and you can test on each platform's webview

Sources: Tauri docs, Webview versions

Examples

Prompts that work, and what comes back

Concrete checks and prompts for a three.js Steam release. The first four apply to a wrapped build, the last to a native rebuild.

Offline launch check

Prompt

Checklist. Unplug the network, launch the packaged build from the Steam client, reach gameplay, save, quit and relaunch.

What you get

Proof that nothing loads from a CDN, that saves land on disk, and that Steam launches the right executable.

First achievement

Prompt

Add steamworks.js to my Electron app, initialize it with my app ID, and grant the achievement FIRST_BOSS when the boss dies. Enable the overlay in main.js.

What you get

One working achievement and a visible overlay in a Steam-launched build, which is the base for the rest of the Steamworks features.

Focus and pause behavior

Prompt

Pause the game loop and mute audio when the window loses focus, and resume on focus. Keep backgroundThrottling at its default.

What you get

A game that stops cleanly on alt-tab instead of drifting at a throttled frame rate in the background.

Long-session memory test

Prompt

Checklist. Play the packaged build for 60 minutes on an integrated-graphics laptop and log memory use every 10 minutes from the task manager.

What you get

A flat or rising memory line. A rising one usually means textures, geometries or render targets that are never disposed.

Native rebuild of one level

Prompt

In Summer, rebuild level1 from my three.js code as the spec, import the level GLB, add collision to the walls and floor, and run the game.

What you get

A playable first level in the engine that you can compare with the wrapped build before committing to a full move.

Games that shipped this way

CrossCode, by Radical Fish Games, is an HTML5 game written in JavaScript on an engine that grew out of impact.js, and it ships on Steam running in NW.js. The studio's own posts show the maintenance side. In September 2018, just before leaving Early Access, they updated NW.js so the game would run faster and more stable. In December 2019 they moved to NW.js 0.35.5 hoping to fix memory leaks reported on Windows and crashes on Linux and macOS.

Vampire Survivors started in 2020 in Phaser, a JavaScript framework. It entered Early Access on Steam in December 2021 and reached its full release on Windows and macOS in October 2022 on that stack. The team moved to Unity with version 1.6 in August 2023, and the announcement promised better cross-platform support and big performance improvements. Game Dev Tycoon is the third well-known case, since Greenworks was written to give it Steam integration.

The pattern is clear. A web stack can carry a game onto Steam and even to a hit. The costs arrive later, as wrapper updates, platform-specific crashes and performance work. The same route works for Phaser, PixiJS and Babylon.js games, since the wrapper only sees a web page.

The cost of shipping Chromium

A wrapped game is a browser running your page. That has consequences a native build does not have.

  • Download size. Electron and NW.js each carry a full Chromium in every build. Tauri avoids that, and its docs put a minimal app under 600 KB.
  • Rendering path. On Windows, Chrome's default WebGL backend is ANGLE, which translates to Direct3D, so your draw calls pass through an extra layer before the driver.
  • Background throttling. Electron throttles animations and timers in background pages by default, which is wrong for some games and right for others. Decide explicitly.
  • The Steam overlay. Valve's docs say the overlay needs a game that renders frames consistently, which web browsers do not guarantee. In Electron, steamworks.js provides a helper for it. In other wrappers, test the overlay early.
  • Memory over time. Long sessions expose leaks in the wrapper and in your own code. Dispose three.js geometries, materials and textures you no longer use.

Why the Windows build comes first

In Valve's August 2026 hardware survey, 93.95 percent of respondents ran Windows, 3.90 percent Linux and 2.14 percent macOS. Steam depots can target Windows, macOS and Linux separately, so ship the Windows build first and add others when you can test them. With Tauri, remember that each platform means a different webview engine for your WebGL code.

When a native engine build is the better route

If the game is growing, with more levels, more animation states, controller support and a longer campaign, the wrapper becomes one more thing to maintain on top of your homemade engine. Moving to a game engine gives you an executable with no browser inside, an editor, physics and animation tooling.

Summer is one option. It is a desktop app for macOS and Windows that is compatible with Godot 4 and builds Windows and macOS versions for Steam. Your glTF models import directly and the JavaScript logic is rewritten in GDScript, with the agent using your code as the spec. For Steam features in a Godot 4 project the usual route is GodotSteam. Check that it loads in your project before you plan around it. Summer does not export to the web, so if the browser version matters, keep it in three.js.

Where to take your three.js game next

Port it to make money

Steam is the natural paid store for a wrapped three.js game. It needs an executable build uploaded with SteamPipe, a store page visible as Coming Soon for at least two weeks, and a Steam Direct fee of 100 US dollars per game that is paid back after 1,000 US dollars in adjusted gross revenue. itch.io can host the web version and a desktop download side by side.

How to publish a game on Steam

Release it on Summer Games

Summer Games is a new store for games made with Summer. It is launching soon. A wrapped three.js game is not built in Summer, so it will not qualify. A version rebuilt in Summer, reviewed, and working as a single-player game first is the kind that will be ready.

See Summer Games (launching soon)

Grow it

On Steam, wishlists carry the launch, and Steam emails everyone who wishlisted when you release. Open the store page early, make capsule art at every required size, cut a trailer that shows play in the first seconds, and send keys to creators who cover your genre. A free browser version is a strong demo.

Make Steam capsule art

Remake it in Summer

If the wrapper is holding the game back, start from a Summer template near your genre, import your glTF models, and have the agent rebuild each system from your JavaScript as the spec. Playtest in the engine after each system until it feels like the original, then ship native builds.

Remake your game in Summer

Frequently asked questions

Can you sell a three.js game on Steam?

Yes. Wrap it in Electron, NW.js or Tauri so it becomes a desktop executable, upload it as a Steam build, and pay the Steam Direct fee for the store page. CrossCode is a well-known HTML5 game that ships on Steam in NW.js.

Electron or Tauri for a WebGL game?

Electron gives every player the same bundled Chromium, so WebGL behaves the same everywhere, at the cost of a large download. Tauri is far smaller because it uses the system webview, but that means WebView2 on Windows, WKWebView on macOS and webkit2gtk on Linux, and you have to test your renderer on each.

How do I add Steam achievements to a three.js game?

Use a Steamworks binding. steamworks.js supports Electron and NW.js and covers achievements, cloud saves and the Workshop. Initialize it with your app ID and call the achievement API when the event happens in your game.

Why does the Steam overlay not show in my Electron game?

Valve's overlay hooks the game's rendering and needs frames drawn consistently, which browsers do not guarantee. With steamworks.js, call electronEnableSteamOverlay() at the end of your main.js and launch the game through the Steam client.

Does Steam accept HTML5 and WebGL games?

Yes, as a desktop executable. Steam does not host web pages, so the game ships inside Electron, NW.js or Tauri, the route CrossCode took with NW.js. Vampire Survivors also shipped on Steam while built on the JavaScript framework Phaser. The Steam Direct fee is the same as for any game, and our guide to publishing on Steam covers the rest of the process.

Do I need a Mac or Linux build?

No. Steam depots are set per operating system, and most games launch with Windows first. Valve's August 2026 survey had 93.95 percent of respondents on Windows. Add macOS or Linux depots when you can test them.

Can Summer turn my three.js game into a Steam build?

Not by converting it. Summer does not read JavaScript projects. What it can do is help you rebuild the game in its engine, importing your glTF models and using your code as the spec, and then build native Windows and macOS versions for Steam.

Make your game. Grow your game.

Even if it is built in another engine.

Free to download for macOS (Apple silicon) and Windows.