For three.js developers

three.js vs Godot, and when to move your game to an engine

three.js draws the frame. Everything else a game needs, you wrote or wired yourself. Here is how to tell when that stops paying off, what carries over to a Godot 4 compatible engine like Summer, and what you rewrite.

The short answer

three.js is a 3D rendering library for the browser, not a game engine. It has no physics engine in core, no animation state machine, no game editor and no desktop or mobile export. Stay on three.js if the browser is your market and the game is small. Move to a Godot 4 compatible engine such as Summer when you need an editor, native builds for Steam, or a team. Your glTF models, textures and audio import directly, and your JavaScript game logic is rewritten in GDScript. Summer does not export to the web today, so if the browser is where your players are, keep the web build in three.js and use Summer for a desktop version.

Most three.js games start the same way. A scene, a camera, a GLTFLoader call and a render loop, and within a week something moves on screen. The trouble comes later. Collision, a character that blends between idle, run and jump, a pause menu, save files, gamepad support, a level you can edit without touching code. In three.js each of those is a library you pick, wire and maintain, or code you write from scratch.

That is not a flaw. The project describes its aim as an easy-to-use, lightweight, cross-browser, general-purpose 3D library, and it does that job very well. For a web-first game with a small scope it is often the right tool. A game engine is a different trade. You give up some control over the frame loop and get an editor, physics, animation tooling, UI and export pipelines that already work together.

This guide is for developers who have a working three.js game, or a prototype that is getting heavy, and want to know whether moving is worth it. It covers when to stay, when to move, a concept map from three.js to Godot 4 nodes, which files carry over unchanged, and what has to be rewritten. The examples use Summer Engine, a desktop engine for macOS and Windows that is compatible with Godot 4, and the mapping holds for stock Godot 4 as well.

What it does

An editor with a play button

Levels are built and tuned visually. You press play and the game runs in its own window with a debugger, a live scene tree and error output, instead of a browser tab and the dev tools console.

Physics in the engine

Godot 4 ships its own 3D physics with rigid bodies, collision shapes, raycasts and a character body for player movement. In three.js the physics examples wire in Ammo.js, Rapier or Jolt through addons, and you keep the meshes and bodies in sync yourself.

Animation state machines

three.js gives you AnimationMixer, a player that plays and crossfades clips. Godot adds AnimationTree with a state machine, transitions and blend spaces, so idle, walk, run and jump become a graph instead of a pile of if statements.

UI and input systems

Menus and HUDs are Control nodes inside the engine, so they work in fullscreen and with a gamepad. Input is a map of named actions that you bind once to keys, mouse buttons and gamepad inputs.

Native desktop builds

Summer builds Windows and macOS versions of your game for Steam and itch.io downloads once the export templates are installed. There is no browser wrapper and no bundled Chromium in the build.

An agent that works inside the engine

Summer's in-app agent, and any coding agent connected through the Summer MCP, can read the scene tree, write GDScript, import assets, run the game and take screenshots. That makes your old JavaScript usable as a spec for the rebuild.

How it works

  1. 1

    Step 1: Decide where the game will be played

    If most players will arrive from a link or a web portal, stay on three.js. If the goal is Steam or a desktop download, moving pays off. Summer does not export to the web today, so a move to Summer means a desktop version.

  2. 2

    Step 2: Audit your assets before import

    List your GLB and glTF files, textures and audio. Re-export any model that uses Draco mesh compression (KHR_draco_mesh_compression) without it, because Godot's glTF importer does not support that extension. Note your world scale, since Godot treats 1 unit as 1 meter and its physics is tuned for that.

  3. 3

    Step 3: Import models into a new project

    Copy the files into the project folder. Godot 4 and Summer import glTF 2.0 directly, in both .gltf and .glb form, with materials, skins and animation clips. glTF, three.js and Godot are all right-handed with Y up, so nothing needs an axis flip.

  4. 4

    Step 4: Rebuild the scene as a node tree

    Make one scene per reusable thing, such as the player, an enemy and a pickup, then a level scene that instances them. A Godot scene doubles as a prefab, so this replaces the factory functions you wrote in JavaScript.

  5. 5

    Step 5: Move the loop into _process and _physics_process

    Per-frame code from your animate() or setAnimationLoop callback goes into _process(delta). Movement and collision go into _physics_process(delta), which runs 60 times per second by default. You no longer call renderer.render().

  6. 6

    Step 6: Rewrite the logic one system at a time

    Port the player controller first, then one level, then the core loop, then UI, then content. Keep the JavaScript open as the spec and copy tuning values exactly, so the new build can be compared against the old one.

  7. 7

    Step 7: Match the camera and compare side by side

    Set Camera3D.fov to the value your three.js PerspectiveCamera used. Both are vertical angles in degrees, but three.js defaults to 50 and Godot to 75, so an unmatched camera makes everything look smaller. Then compare screenshots of the same view.

Two ways to run it

In Studio, or from the agent you already use

In Summer Studio

Summer Studio runs in the browser and generates game assets. If your three.js game still uses placeholder models, generate replacements in the 3D tab as GLB files. They import into Summer and work in three.js too, so both versions can share them. Studio does not build or run games in the browser.

Open the 3D tab in Studio

From Claude, Cursor or Codex via MCP

If you already work with Claude Code, Cursor or Codex, the Summer MCP lets that agent drive the Summer desktop app. It can import your GLB files with summer_import_asset, write GDScript, build scenes, run the game with summer_play and check the result with summer_screenshot. Point it at your old JavaScript files as the spec.

Example prompt for your agent

Read src/player.js and src/enemies.js from my three.js project as the spec. In the open Summer project, import every GLB from assets/models, build a player scene with a CharacterBody3D that uses the same walk speed and jump height, then run the game and send me a screenshot.
Set up the Summer MCP
three.js concepts and their Godot 4 equivalents
three.jsGodot 4 and SummerWhat to watch
Scene, Object3D and GroupThe scene tree and Node3DA Godot scene is also a reusable prefab. Split player, enemy and pickup into their own scenes and instance them.
scene.add(child)add_child(node)Nodes placed in the editor are saved in the scene file, so most setup code disappears.
requestAnimationFrame or setAnimationLoop_process(delta)The engine calls it every frame. Movement and collision belong in _physics_process, which runs 60 times per second by default.
Clock.getDelta()The delta argumentAlready in seconds, as in three.js.
GLTFLoader at runtimeglTF 2.0 imported in the editorFiles are imported once into engine resources instead of being parsed on every load. Draco-compressed files are not supported.
Mesh with MeshStandardMaterialMeshInstance3D with StandardMaterial3DBoth use metallic and roughness PBR, the same model glTF uses, so imported materials look close.
InstancedMeshMultiMeshInstance3DMany copies of one mesh drawn together.
PerspectiveCameraCamera3DBoth fov values are vertical degrees. three.js defaults to 50 and Godot to 75.
AnimationMixer and AnimationActionAnimationPlayer with AnimationTreeThe state machine and blend spaces replace hand-written crossfade logic.
RaycasterRayCast3D or a physics space queryRays hit collision shapes, not render meshes, so add collision to anything you want to pick.
Ammo.js, Rapier or Jolt addonsBuilt-in RigidBody3D, StaticBody3D and CharacterBody3DNo sync code between physics bodies and meshes. The body is the parent node.
ShaderMaterial in GLSLShaders in Godot's shading languageSimilar to GLSL ES 3.0 but not identical, so shaders are ported by hand.
EventDispatcherSignalsDeclared on the node and connectable in the editor or in code.
DOM overlay for HUD and menusControl nodesUI runs inside the engine window, including fullscreen.
addEventListener for keysInput map actionsName an action once and bind keys, mouse buttons and gamepad inputs to it.

Sources: Godot docs, Idle and Physics Processing

Examples

Prompts that work, and what comes back

Things to try in the first days of a move. Each one is small enough to check by eye against your three.js build.

Port the player controller

Prompt

My three.js player code is in old_js/player.js. Rebuild it as a CharacterBody3D script with the same walk speed, jump height and camera follow distance, then run the game.

What you get

A player scene and a GDScript file that can keep your tuning values as exported variables you can adjust in the inspector, plus a running build to compare with the original.

Replace crossfade code with a state machine

Prompt

The robot model has Idle, Run and Jump clips. Set up an AnimationTree state machine that switches on movement speed and on jumping.

What you get

An AnimationTree with three states and transitions driven by the controller, replacing the crossfade logic you wrote around AnimationMixer.

Match the camera

Prompt

My three.js camera used fov 50, near 0.1 and far 1000, placed at 0, 5, 10 and looking at the origin. Set the Camera3D to match and take a screenshot.

What you get

A Camera3D with the same vertical field of view, clip planes and framing, so screenshots from both versions line up.

Rebuild the HTML overlay

Prompt

My game shows the score in an HTML div and has a pause menu in the DOM. Build the same HUD and pause menu with Control nodes and pause the game on Escape or the gamepad Start button.

What you get

A HUD and a pause menu inside the engine that work in fullscreen and with a gamepad.

Collision for picking

Prompt

In three.js I used a Raycaster on the meshes to select units. Add collision shapes to the unit scenes and select them with a mouse ray.

What you get

Units with collision shapes and a click handler that queries the physics space, since Godot rays hit collision shapes rather than render meshes.

Is three.js a game engine

No, and it does not try to be one. three.js renders 3D scenes with WebGL or WebGPU and gives you loaders, cameras, materials, lights and an animation player. The three.js editor at threejs.org/editor composes scenes, attaches scripts and publishes a small player page, but there is no physics in core, no animation state machine, no UI toolkit and no path to a Steam, desktop or mobile build.

Everything a game engine adds sits on top of three.js in your own code or in libraries you choose. That is why three.js games vary so much in structure, and why a large three.js game often contains a small homemade engine. The question is not which tool is better in general. It is whether the engine you have been building by hand is still worth maintaining.

When to stay on three.js

Stay if the browser is the product. A game that lives on a web portal, inside another site, or behind a shared link benefits from three.js being small and native to the page. Portal budgets are tight. CrazyGames wants an initial download of 50 MB or less, and 20 MB or less for its mobile homepage, and a three.js bundle can stay well inside that.

  • Players arrive from a link, a portal or an embed.
  • The scope is small, such as an arcade game, a puzzle or a toy.
  • You like owning the render loop and writing everything in code.
  • The game has to share a page with other web content, such as a product site or a campaign.
  • Your physics and animation needs are simple enough that one library covers them.

When to move to a game engine

Move when the work around the renderer takes more of your week than the game does. The signs are consistent.

  • You want Steam or a desktop download. Windows was on 93.95 percent of respondents' machines in Valve's August 2026 Steam survey, and a native build there avoids shipping a browser inside your game.
  • Levels are getting hard to build in code and you want an editor.
  • Characters have many animation states and the transition logic keeps breaking.
  • Someone who does not write JavaScript needs to work on the game, such as an artist or a level designer.
  • You have already written your own scene serialization, physics sync or asset pipeline, and maintaining it is slowing you down.

What carries over and what is rewritten

Assets carry over. Godot recommends glTF 2.0 as its 3D format and imports both text and binary files, so the same GLB your GLTFLoader reads becomes a scene with meshes, materials, skeletons and animation clips. PNG and JPG textures import as they are. Audio in WAV, Ogg Vorbis or MP3 imports directly. Level layouts stored as JSON can be read from GDScript, and every tuning value in your code is worth copying exactly.

Code does not carry over. There is no converter from JavaScript to GDScript that produces a working game, and the structure is different anyway. Game logic, input handling, UI, physics glue and shaders are all rewritten. The good news is that a working three.js build is the best spec you could have. You know exactly how the game should feel, and you can compare each rebuilt system against it.

Pitfalls in the first week

Most problems after a move come from a few small differences between the two worlds.

  • Draco-compressed models fail to import. Keep uncompressed originals or re-export without compression.
  • An unmatched camera makes the scene look wrong. Copy the fov, near and far values.
  • A world built at a different scale behaves oddly in physics. Scale on import so 1 unit is 1 meter.
  • Picking stops working. Add collision shapes, because rays test physics shapes, not meshes.
  • Shaders do not compile. Godot's shading language is close to GLSL ES 3.0 but uses its own entry points and built-ins.

Summer and the web today

Web export is not available in Summer yet. Browser play is a research preview. If your players are in the browser, keep shipping the three.js build there and use Summer for a desktop version on Steam or as an itch.io download. The two versions can share models, textures and audio, while the code lives in two places.

That split costs maintenance, so it makes sense when the desktop game can be bigger than the web one, with more levels, a gamepad, a longer campaign or a paid release. A common pattern is a small web game that acts as the demo and a desktop game that is the product.

Where to take your three.js game next

Port it to make money

Steam is the paid store most three.js developers aim for. It needs a desktop build, either your web game wrapped in Electron, NW.js or Tauri, or a native build from an engine. Steam charges a Steam Direct fee of 100 US dollars per game, paid back after the game earns 1,000 US dollars in adjusted gross revenue, and the store page must be visible as Coming Soon for at least two weeks before release.

Ship a three.js game on Steam

Release it on Summer Games

Summer Games is a new store for games made with Summer. It is launching soon. A three.js build will not qualify on its own. The games that will be ready are built in Summer, have passed a review, and work as single-player games first.

See Summer Games (launching soon)

Grow it

Web games get players from portals and links, desktop games get them from wishlists. Put up a store page early, cut a trailer that shows play in the first seconds, and send builds to creators who cover your genre. A free web version can be the demo that feeds the wishlist.

Market your indie game

Remake it in Summer

Start from a template close to your genre, import your glTF models, and have the agent rebuild each system from your JavaScript as the spec. Playtest in the engine after every system and compare it with the three.js build until the feel matches.

Remake your game in Summer

Frequently asked questions

Is three.js a game engine?

No. three.js is a general-purpose 3D rendering library for the browser. It has loaders, cameras, materials and an animation player, but no physics engine in core, no animation state machine, no game editor and no desktop or mobile export. Games built on it add those pieces with other libraries or their own code.

Is Godot better than three.js for games?

For a game that ships on Steam or as a desktop download, a game engine like Godot 4 or Summer saves you from building physics, animation, UI and export yourself. For a small game that lives in the browser, three.js is lighter and fits the page better. Pick by where your players are, not by which tool is more powerful.

three.js vs Unity, which should I use?

The same split applies. Unity and Godot are full engines with editors and native builds, and three.js is a browser renderer. If you are moving from three.js, Godot 4 and Summer keep a lightweight, code-first workflow and import your glTF files directly.

Can I convert my three.js code to Godot automatically?

No tool converts a JavaScript game into a working Godot project. Models, textures and audio import directly, and the logic is rewritten in GDScript. Summer's agent can use your JavaScript files as the spec and rebuild one system at a time, which you then playtest against the original.

Do my GLB files from three.js work in Summer?

Yes, in most cases. Godot 4 and Summer import glTF 2.0 in .gltf and .glb form with materials, skins and animations. The exception is Draco mesh compression, which Godot's importer does not support, so re-export those files without it.

Can I put my three.js game on Steam instead?

Yes. Wrap the web build in Electron, NW.js or Tauri so it becomes a desktop executable, add Steam features through a binding such as steamworks.js, and upload it as a Steam build. Our guide to three.js games on Steam covers each wrapper and the performance costs. A native rebuild in an engine is the other route.

Which language do I write in after moving?

GDScript, which is close to Python in syntax and built for the engine. C# is available in the Summer desktop editor. JavaScript and TypeScript are not used for game code.

Can I keep a web version and a desktop version?

Yes. Many teams keep the three.js game on the web as a demo or a free version and build the desktop game in an engine. Share the glTF models, textures and audio between them and accept that the code is maintained twice.

Make your game. Grow your game.

Even if it is built in another engine.

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