Troubleshooting
Diagnose common editor, Lua, animation, physics, publishing, and MCP problems.
An object has vanished from my scene
It has almost certainly not been deleted. When a scene object's stored data cannot be read, the editor skips that object and opens the scene anyway, rather than refusing to load at all. A panel appears at the top of the viewport saying how many objects failed to load.
If you dismissed that panel, or closed the scene before reading it, the object simply is not there — and it will be skipped again on every load until its stored data is fixed. Reload the scene to bring the panel back.
From each row you can:
- Retry — load that object again. Enough if the failure was transient, such as an asset that had not finished uploading.
- Copy — copy the object's id, the error, and its stored data, formatted to paste into the AI assistant or an MCP client. This is usually the fastest repair, because the text already contains the data that failed to load, which is what a fix has to change.
- Delete — remove it permanently, if it is not worth repairing.
- Dismiss — hide the row. This repairs nothing; the object is still broken.
The panel also lists objects that did load, but were built from something other than what they reference — a terrain whose height map could not be read, for instance. Those rows are amber rather than red and are marked in the scene. They offer no Delete: the object is standing and rendering, and deleting it would take everything parented to it as well. Retry is the remedy, since whatever it could not read may have arrived since.
An object can also vanish because the server refused to save it. Such an object exists only in your editor tab, so it is gone the next time the scene loads. The panel lists it in red, marked not saved to server, with the server's reason: for example a parent it cannot have, a scale the physics engine cannot simulate, or an id already used in the scene. Fix the cause and edit the object again; the row clears once a save succeeds. These rows offer Select, Copy, and Dismiss. A save that could not reach the server at all is not listed.
A common cause is a deleted asset. Deleting an asset does not clear the objects bound to it, so check whether anything was removed from the asset library recently. What happens next depends on what the missing asset was for, and only the first two make an object disappear:
- A mesh asset on a mesh or ragdoll object — the object cannot be built at all and is skipped.
- A chassis mesh on a vehicle — the same, the vehicle is skipped rather than falling back to a box.
- A height map on a height field — the terrain still loads, but it is built from procedural noise instead of the image that was bound, so you get a hill of the wrong shape rather than no hill. If terrain you authored suddenly looks generic, this is why.
- A colour map on a height field — the terrain loads untextured, showing its material's colour with no image on it.
See When an object fails to load.
An object will not take a parent
Water cannot be a parent, and a GUI element and a 3D object cannot be parent and child in either direction: GUI elements nest through their own parentObjectId. The editor's hierarchy will not offer these links, and the server refuses them from MCP tools and the AI assistant with validation_error and the message cannot be water or cannot link a GUI element and a 3D object. An object already inside water from an older scene can still be edited, and moved out.
A script never runs
Confirm the script is attached to the correct object, simulation is running, and the browser console has no initialization error. Scene-wide scripts must be assigned in Scene Settings.
If the object is bound to a script the project does not have — one that was deleted, or an id that was never right — the issues panel says so, listing it as an object that loaded but does nothing. There is no error to find in the console for this one: nothing failed, the script simply was not there to run.
Before 16 September 2026 a script created by the AI assistant, or the driver script vehicles_create_wheeled writes for a new vehicle, did not reach an editor tab that was already open, so an object bound to it stayed inert until the page was reloaded. A vehicle in that state looked like a broken drivetrain: physics_run_simulation reported driver input stuck at zero with an empty script_errors list, which is exactly what a script that runs and does nothing leaves behind. Reloading the tab fixed it.
A first-person camera never turns
First-person consumes every look producer. Try the arrow keys first. If they work, enable Desktop mouse look for mouse aim, or enable mobile controls and author a look stick for touch. Click the canvas to capture the mouse and press Escape to release it.
Also confirm the camera has no scriptId and that targetCharacterId resolves to the intended character, vehicle, or other transform-bearing object. A missing target falls back to free-camera behavior; a script disables the built-in controller.
Arrow keys do not orbit my third-person camera
That is expected. Arrow keys and the touch look stick feed the Lua look bus; the starter Character Controller uses them to turn the character, and the third-person boom follows that rotation. Independent third-person orbit comes from pointer look: mouse movement when Desktop mouse look is enabled, or a touch drag away from the controls.
This split prevents one held turn from rotating both the character and the boom. If neither the target nor the camera moves, check the target's controller script. If the character turns but independent orbit does not work, enable Desktop mouse look or test touch drag. There is no gamepad support.
I can see my own character in first person
Both first-person modes hide the followed object from their own view by default, so a character's head and body no longer cross the screen when you look down or sideways. If you can still see it, check the camera's Hide followed object setting (hideFollowedObject); false turns the hiding off. Only that camera's render is affected: other cameras and other players still see the character, and its collisions and animation are unchanged. A game published earlier picks this up once republished.
First-person look stops short of straight down
That is the camera's pitch limit. Set Minimum Pitch (degrees) and Maximum Pitch (degrees) (minPitch/maxPitch, positive up) on the camera: minPitch: -60 stops downward look at 60°. Left unset, first-person look stops at about ±87° and third-person orbit at ±60° from the authored boom. A camera with a script supplies its own limit.
The first-person view faces the wrong way
A first_person camera renders along its target's forward axis, local +Z — the direction the character faces. If the view starts out pointing behind the character, the usual cause is a 180° correction left over from before 9 September 2026, when the mode did not reconcile Three.js's -Z view direction with the engine's +Z forward and the view did start out backwards.
Look for a half-turn applied to the character, to the camera, or in a script that writes either one's rotation, and remove it. A scene that was authored to look correct under the old behaviour is exactly the scene that looks backwards now.
If the view is not reversed but merely points somewhere unexpected, check the character's authored rotation — the camera inherits it, so the character's facing is the view's resting direction. getForward() on the camera reports the rendered direction and can be printed to confirm.
The first-person camera sits too high or too low
Set the camera's eyeHeight field to the eye height you want. It is measured from the follow target's origin, which for a character is its feet, so eyeHeight = 1.65 puts the eye at 1.65m. The default is 1.6.
followOffset.y is added on top of eyeHeight, not used in place of it. A scene that puts the whole intended eye height into followOffset.y therefore ends up about 1.6m too high — which looks like the world is the wrong scale. Leave followOffset.y at 0 unless you want a further nudge.
A material colour is rejected
materials_create and materials_update take colour channels as normalized values from 0 through 1. A channel above 1 is an error rather than a bright colour, and so is a key other than r, g, or b. This applies to color, specular, emissive, and sheen alike. Divide an 8-bit value by 255: {r: 204, g: 102, b: 0} becomes {r: 0.8, g: 0.4, b: 0}. See Assets, materials, and shaders.
A material's normal, roughness, metalness or AO map is refused or has no effect
Only standard and physical materials render these maps. materials_create and materials_update refuse normalMapId, roughnessMapId, metalnessMapId, aoMapId, normalScale and aoMapIntensity on a phong, basic or lambert material with validation_error, and the editor shows their pickers only for the two PBR types. Change the material's type, or bind only a colour map (mapId).
A roughness or metalness map that seems to do nothing is being multiplied by the material's Roughness or Metalness value: with metalness at 0 a metalness map has no effect at all. Set the value to 1 to use the map as painted. The renderer reads roughness from the green channel, metalness from the blue and ambient occlusion from the red, so a single-channel image saved in another channel reads as empty. See Assets, materials, and shaders.
A material does not apply to an imported model
Work down the resolution order for the surface in question. A named surface with its own binding in surfaceOverrides wins; otherwise the object's own materialId applies; otherwise — while the object is on Default White — the model keeps the material embedded in the file.
So a model that still looks the way it was exported, despite an object material being set, usually has per-surface bindings covering the parts you are looking at. A model that will not take an override at all is usually skinned: an animated character's skinned geometry always keeps its imported material, and neither kind of override replaces it.
A surface binding names a project material by ID, and deleting that material puts the slot back on its embedded material while keeping the binding — the inspector then shows Missing material, which is the quickest confirmation that this is what happened.
A material renders as nothing at all
A shader material whose vertexShaderId or fragmentShaderId points at a shader that has been deleted cannot compile, so objects using it do not render — they disappear rather than falling back to a default surface. Repoint the material at an existing shader, or change its materialType to one of the built-in surface models.
A vehicle's wheels ignore its material
That one is deliberate. Tires, rims, and track belts are drawn from the vehicle's physics wheel layout rather than from its chassis model, so they never inherit the object's Material — a red car should not arrive on red tires. Colour them with the vehicle's own Tire Color, Rim Color, and Track Color fields, in the inspector or through scene_objects_update. Leave one unset and it keeps its default rubber or steel. See Vehicles, constraints, ragdolls, and navigation.
An action button works on touch but does nothing on desktop
Inspect the action's authored keys. Each action may bind up to four KeyboardEvent.code values or Mouse0/Mouse1/Mouse2. An action with no authored keys falls back to its positional digit, 1 through 9; jump and primary_fire keep Space and left mouse as compatibility bindings. If two actions claim one code, the later authored action wins. An action omitted from the button list has no route on either device.
The mirror of this catches people on mobile: an action button is the only touch source for its action, so a mechanic gated behind an action whose button was never added is unreachable on a phone even though the keyboard shortcut works.
Look is far too fast, too slow, or inverted
Sensitivity and per-axis invert are player settings, not scene settings. Open the Preview menu and choose Look controls—available on desktop and touch—to adjust them between 0.5x and 2.0x. They are stored per viewer, so what you see is not necessarily what your players see.
In Lua, read lookDeltaX/lookDeltaY and not lookAxisX/lookAxisY. The engine integrates the held axis into the deltas once per frame, so a script that reads both turns twice as fast as it should.
Collision callbacks never fire
Call gameObject.registerForCollisions() inside init(). For trigger callbacks, also enable Trigger Volume on the sensor object.
When the object entering the trigger is a character, the trigger fires once the character's script has finished init(), whether or not it registered for collisions; only a character script that wants its own onTriggerEnter needs registerForCollisions(). Before 3 October 2026 a character whose movement script never registered could not set off a trigger at all, so a checkpoint or pickup that never fired in an older release may start working when the game is played again.
If the two objects collide with everything except each other, check whether they share a collision group with that subgroup pair disabled — that is exactly what the filter is for, and it suppresses the contact callbacks along with the contact. See Collision groups.
A character and a solid body it touches both receive onCollisionEnter and onCollisionExit, including the floor the character stands on. Until early October 2026 a character reported no solid contacts at all — a thrown ball stopped against it and neither side was told — so a script written around that, for instance one that detects hits with a trigger instead, may now see both.
A trigger reports contact but nothing happens
The handler probably ran and raised. A Lua error inside a callback stops that callback where it stands, and the object it was about to move simply does not move — which from the outside is indistinguishable from a trigger that never fired.
The usual cause is treating the callback argument as an object. other is a plain data table — id, position, rotation, normal, contactPoint, contactDepth, isTrigger — with no methods on it, so other.setPosition(...) is nil and calling it raises. Resolve it first:
function onTriggerEnter(other)
local entered = gameObject.getObject(other.id)
if entered then
entered.setPosition(0, 5, 0)
end
end
Check the browser console for the error, or run physics_run_simulation and read script_errors, which lists every error a script raised during the run with the callback it came from and how many times it happened. An empty script_errors alongside a recorded contact means the handler really did not run — go back to the registration checks above.
A soft body will not move when a script pushes it
Work down these four, in order. The first two are the usual answer.
- Check the method name. There is no
applyImpulseon any kind of object — the method isaddImpulse.ball.applyImpulse(...)isnil, so calling it raises and stops the rest of the handler, which then looks like a push that did nothing. - Check the magnitude. A soft body's mass is its vertex count: every simulated vertex weighs 1 kg, so the default soft sphere is 162 kg and a finer tessellation weighs more. The object's Mass field does not apply to a soft body and is ignored. An impulse tuned against a rigid sphere of the same size is roughly two orders of magnitude too small.
- Do not assign velocity.
setLinearVelocityandsetAngularVelocityare discarded on a soft body — its velocity is recomputed from its vertices every step — so useaddImpulseandaddTorqueinstead. The getters are fine and report the body's real motion. - Remember that force is per-frame.
addForceandaddTorqueare consumed by the next physics step and then cleared, so a single call fromonTriggerEnterlasts one frame. For a one-off shove useaddImpulse; to push for longer, calladdForcefromupdate(dt).
Before 16 September 2026, addImpulse and addTorque did nothing at all on a soft body and raised no error to say so; only addForce worked. If you are testing an older published release, that is the behaviour you are seeing — republish to pick up the fix.
A ragdoll jitters or explodes
Adjacent bones overlap at every joint, so their capsules push each other apart on the first step. Put the ragdoll's bodies in a shared collision group and disable the neighbouring subgroup pairs — see Collision groups.
If it collapses rather than buzzes, check the joint limits. Setting a ragdoll-wide default replaces the per-bone anatomical presets, so one generous cone applied to every joint gives elbows and knees that bend both ways. Use per-bone overrides for the joints that are actually wrong. See Ragdolls.
An animation is not found
Print gameObject.getAnimationNames() and copy the exact case-sensitive clip name. Confirm the mesh actually contains animation tracks.
On a character with no mesh asset of its own, the clips are the bundled model's, and they are listed in Animation playback API. That model gained a much larger set on 14 September 2026 and lost its old tpose clip, so a script written against the previous four names is the one case where an existing scene can start missing a clip it used to find.
A character moves but never changes pose
A character animates only if something asks it to. enableAutoAnimation(config) on its own does nothing — it also needs updateAutoAnimation() called every frame, and called at the end of update() so it reads the movement applied that frame rather than the previous one.
If it animates but never leaves idle, check that the script is actually setting velocity: the state machine reads getCharacterVelocity(), so a controller that moves the object by writing its position instead will look motionless to it.
A character's death or crouch clip leaves it floating
A character's clips keep the vertical movement of the hips, so a death, crouch or roll clip lowers the body to the floor, and only the horizontal drift of the root bone is removed to keep the model on its capsule. Before 9 October 2026 the engine removed all of the root bone's movement, so a character playing a death clip lay at waist height. Clips added with Add Animation were not filtered at all then, so a Mixamo clip from a separate file could walk the model away from its capsule. Both are fixed. If a character still slides away from where it stands during a clip, the clip is moving it horizontally on purpose and your script should move the character instead. See "Root motion" in Animation playback API.
The console fills with PropertyBinding warnings, or a clip plays as a collapsed or twisted pose
The clip was made for a different skeleton from the model, or in different units. Print gameObject.getAnimationDiagnostics(), or open the model's animation preview in the inspector and read its Rig compatibility box:
"partial"with a list of missing bones, often fingers or toes, means the model leaves out bones the clip animates. Those tracks are dropped and the rest of the clip plays; the console gets one line for the clip rather than a warning per bone."incompatible"means no track names a bone in the model. Retargeting is not supported: export the motion from the same rig as the model (for Mixamo, download it for this character).- A
positionScaleof about 100, or about 0.01, means one file is in centimetres and the other in metres, which collapses or explodes the pose. Re-export one of them so their units match.
See "Check that a clip fits the model" in Animation playback API.
A vehicle is a plain box
Every vehicle preset loads a bundled model — a pickup for the wheeled presets, a sport bike for the motorcycle controller, a tank for the tracked ones — and draws a box the size of its physical chassis only when that model could not be fetched. A box therefore means the model request failed rather than that the vehicle was never given one: check the browser console and reload.
A Chassis Mesh you chose yourself behaves differently. If that asset has been deleted from the project the vehicle does not fall back to a box at all — it fails to build, and reports the missing asset as a scene load issue. See When an object fails to load.
A vehicle will not move
Almost always this is the vehicle's own driving script rather than the physics. A driving script calls gameObject.setDriverInput(...) every frame from the shared input bus, so driver input set from anywhere else — another object's script, a diagnostic, the REPL — is overwritten on the very next frame. Zero driver input then lets the settled chassis fall asleep, and Jolt's vehicle step listener returns early for a sleeping body, so nothing moves at all.
To drive a vehicle from a test or a headless run, set the movement bus (moveAxisY for throttle, moveAxisX for steering) and let the vehicle's own script convert it. Do not call setDriverInput from outside that script and expect it to survive a frame.
physics_run_simulation answers this directly. A wheeledVehicle or trackedVehicle sample carries three fields, and between them they separate the three causes that all look identical if you read only the speed:
vehicle_driver_input— read back off the controller, so it is what the vehicle is actually being asked to do rather than what you last asked it.forward: 0while you believe you are applying throttle means something is zeroing it every frame.vehicle_wheel_contact— one boolean per authored wheel, in order. All false means the wheels are not reaching the ground: check the spawn height, the suspension length against the wheel radius, and that the ground collider is really there.body_active— false means the chassis is asleep. Non-zero driver input wakes it; zero input will not.
The run summary carries wheels_ever_in_contact and max_abs_driver_forward_input for the same question without reading every sample. Wheels in contact with a forward input of 0 is a throttle problem; wheels never in contact is a geometry or spawn-height problem.
Triangle-mesh colliders, including generated road and terrain meshes, do support vehicle wheel casts. If the wheels report contact, the ground is not the problem.
The editor Lua REPL reports success but nothing changed
The REPL is read-only by default, so create, update, and delete quietly do nothing until Apply scene changes is ticked—create returns nil and the others return false. Writes are also refused while a simulation is running, so stop the simulation first. If apply is on and the simulation is stopped, check the field names: update only writes fields the object already has, and ignores id and type.
Editor Lua globals are missing
gameObject, scene, input, and gameStorage only exist in Lua attached to an object or a scene during simulation. The editor REPL and scripting_run_editor_lua get a single editor global instead. Conversely, editor does not exist inside an attached script.
An MCP tool cannot find a project or scene
Call accounts_list first, use the returned account ID, then list projects and scenes within that same account. Scene IDs are UUIDs; project and account IDs use prefixed IDs.
An archived project returns not_found from every tool, not just from projects_list, and so does everything inside it. Unarchive it in the editor if you meant to keep working on it.
An MCP tool says the scope is insufficient
The message names the scopes the call needs. Re-authorize the client and approve them — retrying will not help, because the token itself is missing the grant.
The most common surprise is that scopes are flat: objects:write does not include objects:read. A client granted only write access can create objects but cannot list them. See Connect an MCP client.
MCP physics or editor Lua says the editor is unavailable
physics_run_simulation, scenes_take_screenshot, and scripting_run_editor_lua all run inside a real editor tab rather than on the server. Open the exact project and scene in a visible editor tab, let it finish loading, keep the tab active, and try again. Each request waits only briefly for a tab to pick it up — 20 seconds for a screenshot, the run's length plus 10 seconds for a simulation, and 30 seconds for editor Lua — so a tab that is still loading the 3D engine when the call arrives can miss it—retrying once the scene is on screen usually succeeds.
A tab in the background does not count: the browser pauses its animation loop, so a simulation fails with "The editor tab must be visible". If your client automates a browser that is not signed in, call scenes_open_editor_link and open the editor_url it returns there. The link opens this scene's editor without signing that browser in. See the MCP tool guide for how long it lasts and why a reload goes to the sign-in page.
A multiplayer game will not publish
The Publishing section lists each refusal with the scene, object, and script it is about, and says what to change. The ones new authors meet most:
- A scripted object has no role. Every scripted object that is not bound to a player slot, and is not a camera or GUI element, needs its Script runs on setting (
multiplayer.scriptRole) set to"authority"(runs on the room server, everyone sees it move, gameplay collides with it) or"presentation"(decoration, run in each browser, no collider). In a project created before 25 September 2026, the old starter Fall Zone, Fall Detector and Restart button are the usual source — delete them. A new project's starter scene already publishes as a multiplayer game. - A control script reads the clock, or uses the result of
multiplayer.fire,setController,setPrimary,hold,release,spawn,despawn,destroy,moveTo,followPath, or object creation. The player's browser replays that script and cannot know those answers. Count time fromdeltaTime, and call those functions for their effect only. - A script other than the scene script calls
scene.loadSceneorscene.restart. Only the scene script may change scene in a room. Have the player ask with an action, and change scene from the scene script'sonPlayerAction. - A GUI, camera, or presentation script changes the game — a state setter,
setVar,pauseGame,fire,sendEvent,destroy. Send an action and let the scene script do it. - Too many replicated objects or wheels. A room shares at most 32 placed objects per scene — authority scripts plus objects with Replicate on (
too_many_replicated_props) — and at most 10 wheels per vehicle (too_many_vehicle_wheels). - Two multiplayer settings contradict each other (
conflicting_multiplayer_settings): a player's character or vehicle declared presentation or marked to replicate, an object both replicated and presentation, or a camera or GUI element declared authority. Remove one of the two. A setting nothing reads where it is — Follow local player on anything but a camera, a respawn delay or kill height on anything but a spawn template, a script role on an unscripted object — is only a warning (ignored_multiplayer_setting). - A weapon is unknown or on the wrong object.
unknown_multiplayer_weaponmeans an object's Weapons setting names a weapon the project's combat library does not define — usually one renamed or deleted since.unsupported_weapon_ownermeans weapons on something other than a character or vehicle. A weapon nothing carries is a warning (unequipped_multiplayer_weapon), and in a roommultiplayer.firereturnsnot_equippedfor a weapon the firing object does not carry. - A replicated object cannot be shared.
unreplicable_multiplayer_objectmeans Replicate is on a soft body or another object the room server cannot move.static_replicated_objectwarns about a static, unscripted object marked to replicate: it never moves and still takes one of the scene's 32 shared objects. - A player slot is on something other than a character or vehicle. Nothing else is shared with the other players, so a slot there moves nothing. Remove the slot and give the object a script role (
multiplayer.scriptRole) instead, or turn on Replicate if it is an unscripted physics object. - Nothing a player does can reach the game. A multiplayer game needs at least one player slot, a character or vehicle spawn template, or an authority action. And if it declares authority actions, at least one scene needs a scene script, because only a scene script's
onPlayerActionreceives them. - A spawn template cannot be copied into a room. Give each template in a scene its own name, no player slot — hand each copy to its player with the spawn's
controlleroption instead — and no script below its root. A template may not be or contain a camera, a GUI element, a constraint, a ragdoll, cloth or another soft body, a height field, or water, and a scene may declare at most 32.
An MCP client reads the same list, with a code and a hint for each item, from projects_publish_check. See Build and test a multiplayer game.
A published game shows "Game unavailable"
If the message underneath reads The multiplayer metadata is invalid., The multiplayer combat templates are invalid., or The multiplayer event schema is invalid., the live release's multiplayer settings are malformed. Republish the project; publication lists anything that has to change first.
If it reads This game uses unsupported runtime schema followed by a number, the live release was built for an older player. Republish the project. Every game published before 8 October 2026 needed this once.
A script works alone but raises an error in a multiplayer room
In a room each script runs either on the room server or in players' browsers, and each side may only call part of the API. The error names the call and where it may be used instead. Two patterns cause most of them:
- Presentation from the room server. Sounds and music, GUI setters, light changes, the active-camera calls, and
gameStorageraise in the scene script and in a character's or vehicle's control script, and the error stops the rest of that callback — so a control script that callsplaySoundpart-way throughupdateskips everything after it. Move those calls to a GUI, camera, or presentation script. Publication does not catch this one; only a room does. Animation calls are the exception: in a control script they are accepted and do not raise. - Gameplay from a browser. A GUI or camera script calling a state setter,
setVar,pauseGameorresumeGame, or moving an object other than its own.
The scene script does nothing in a room, and no player sees an error
In a room the scene script, and any object declared "authority", runs on the room server, and its errors are reported there — never in a player's browser console. An error stops the rest of that callback, so a score that never changes or a round that never resets usually means a line in the scene script raised. Open the project and choose Script errors in its Publishing section to read the errors the game's rooms caught, with the object, script, callback and message, or run the scene in the editor, where every script's errors are shown as they happen. A presentation call from the scene script, such as setting a label's text or playing a sound, is the most common cause and raises only in a room.
Nothing spawns in a room
Read the second value multiplayer.spawn returns. unavailable on every call means the script is not an authority script, or the simulation is not running. unknown_template means no template in the scene has that name. spawn_limit means 32 copies are already live, so look for copies that never end. If the copy appears but a player's camera stays put, aim the camera at the template rather than at a placed character. See Build and test a multiplayer game.
My character stutters or snaps back in a room
Your own character moves on your screen before the room server confirms it, and is corrected when the two disagree. Persistent snapping means the control script takes a different path on the room server than on your browser. Check that it does not branch on the result of a call only the room server can answer, and that nothing else writes to the character every frame. A single snap after a respawn or teleport from the scene script is expected.
A player drifts sideways with no input
Something solid overlaps the player's capsule, and the character is pushed out of it every frame. The usual cause is decoration attached to the player or to its camera, such as a first-person weapon, a hat or a backpack, built from cubes or cylinders. Turn on Visual Only on each part (collisionType: "none" through MCP), so it has no collider. Do not use Trigger Volume for this: a trigger still stops raycasts and still fires trigger callbacks. In a room, unscripted parts under a "presentation" object already have no collider. See Physics, collisions, and triggers.
Players walk through a moving object in a room
The object is declared "presentation". A presentation object has no collider in a room — players, raycasts, triggers, and shots pass through it — and each browser moves its own copy. If gameplay should touch it, declare it "authority".
A multiplayer HUD never receives events
onMultiplayerEvent runs on GUI, camera, and presentation scripts only — not on the scene script, which runs on the room server. Move the handler to a GUI script. For your own events, check that each name is declared in the project's presentation event schema and that the release was republished after declaring it.
Other players' characters animate with the wrong clips
In a room every browser animates every character from its movement, and it uses the default clip names — idle, walk, run and the rest — for everyone else's character. A custom enableAutoAnimation configuration in a control script applies only on the controlling player's own screen. Give a multiplayer character a model whose clips use the default names; the bundled default character does. If a character stops animating on one browser, check whether a GUI or camera script played or stopped a clip on it: that takes the character over on that browser, and the automatic animation stands down.
A player cannot send or receive preset messages
If the message button and the lobby's message row are missing for one player, a linked guardian has turned preset messages off for them, and nothing is delivered to them either. If a message is refused, the player sent too quickly: one message a second and eight in 30 seconds are allowed. A player never receives messages from someone they have blocked or who has blocked them. From a script, multiplayer.sendPresetMessage returns the reason as its second value. See Build and test a multiplayer game.
Publish game is disabled
The Publishing section shows the exact blocking reason. Resolve its readiness errors, wait for an existing build to finish, or unpublish another game if the account has reached its active-game limit. Only account administrators can publish.
The initial scene needs an active camera
Open the project's initial scene, add or select a camera, and enable Active Camera. A camera in another scene does not satisfy the initial-scene readiness check.
Publishing failed or appears stuck
Publishing progress is persisted and updates automatically, so reload the project page first. A failed release shows its version and the error that stopped it, or says it was built but could not go live. Correct the project and publish again. A build that stops responding, for instance after a worker restart, is ended automatically within about half an hour with Publishing stopped responding and was ended, and can then be retried.
A republish failed but the old game still works
This is expected. A new release does not replace the live version until its bundle and assets are ready. A failed republish leaves the previous successful release active at the same URL.
A public game URL returns 404
Confirm the game is still published and that the complete generated hostname was copied. An unpublished game, deleted project, malformed hostname, unknown hostname, or project with no successfully activated release returns the same generic 404 response.
The published game works on desktop but not on a phone
Test the public URL on the target device and review the Publishing warnings. Large or unoptimized assets can exhaust a phone's memory even when the project works on a desktop. Reduce textures and meshes, let convertible assets finish optimizing, then republish.