Engine v5.2.4
July 19, 2026
A patch to Lume.
- Fixed top-down (2d-top) characters colliding ~1m south of where their sprite stands: walking into a wall from the north stopped short, from the south overlapped, and the debug collider circle drew below the character's feet. Colliders now sit exactly at the sprite's feet regardless of the object's rotation.
- Camera scripts can now say exactly who owns the view: declare
orientation: { source: "script" }on a custom camera and the screen shows precisely what the script authors (death cams, cinematics, forced framing — even while reading the mouse), orsource: "look"for engine mouse-look at your declared sensitivity withgetViewAngles()to read back what's on screen. Existing cameras are completely untouched — nothing changes unless a camera declares. - Glowing models are back: materials using
glowTexture: true(an emissive tint that glows through the model's own texture) render their glow again instead of a flat solid color — including rigid attachments on rigged characters, which now glow in the same tint as the rest of the model. If you putglowTextureon a model with no texture, on a scripted material or scripted part, or on a part that also wears its own texture, the engine now tells you why nothing glows instead of staying silent. - iPhones opening a game they hadn't touched yet could get permanently marked as "slow devices": iOS slows the page's drawing until the first tap, the engine misread that slowdown as graphics overload, cut visual quality to the floor, and remembered the floor for every future visit. It now recognizes browser-limited frame delivery — even the deep kind — keeps the quality you actually earned, and never lets that state write itself into the device's memory.
- For devices that were already stuck at low quality by the old behavior: recovery is gradual by design — a stored quality setting fades out over 7 days unless a session confirms it, and one quality step lost at startup comes back each session, so a previously-affected device climbs back over its next few sessions rather than instantly.
- Worlds now load in whole scenes instead of objects popping in one at a time.
- God-mode clicking is more predictable: invisible helper objects no longer steal your click from the visible thing under the cursor, and parts glued to a character's bones no longer half-select.
- Long trails and heavy effects stop cutting out mid-stream in effect-dense worlds.
- Path glows and other fading trails now fade all the way out instead of leaving a faint ghost.
- Games can now upload images at runtime and use them as real assets (player-drawn art, generated posters, photo walls).
- Objects spawned with a
lifetimenow expire on schedule even if the player whose behavior spawned them disconnects or refreshes mid-lifetime — no more leftover markers, projectiles, or effects haunting a room until it restarts. - Slow, precise camera look — orbiting an object while keeping it centered, fine aim adjustments — no longer stutters against the frame rate, especially on trackpads and high-refresh displays. Fast flicks are untouched: full speed, no added latency.
- Invisible data-holder objects (like a leaderboard's storage object) now show up in tag searches again — no more "No survivors yet" over a board that actually has scores.
- Scripts that chain thousands of
.add()/.mul()steps onto actx.paramsvalue in a loop now keep that param live-patchable — changing it updates the material in place instead of silently rebuilding the whole shader every time. - Scripts that build very long material or look chains in a loop (thousands of
.add()/.mul()steps) no longer crash the material rebuild with a "Maximum call stack" error — they compile and draw like any other material. - Single-player save systems now actually save your game: auto-saves, load-on-join, and save-on-exit hooks run inside the world you're playing instead of a stale server copy — no more progress resetting to an old snapshot after you close the game, and no more live sessions getting wiped back to a first-quest state by a reconnect.
- Single-player saves stop fighting a ghost: auto-save code in your behavior scripts used to also run in a hidden stale copy of your world, which kept overwriting the real save with day-one data. Now only the world you're playing in writes your storage.
- Walking and moving character sprites no longer ghost or smear under the high-quality upscaler — sprites now tell the renderer exactly how they moved each frame.
- Fixed
getTerrainHeight()(andgetTerrainNormal()) sometimes answering from the lower-detail terrain a device happens to be rendering — on stepped-down devices hilltop heights could read several meters low, so scripts placed or "corrected" objects into the ground. Height reads now always answer the true authored terrain, matching wherey: { terrain: N }placements actually land, on every device. - A physics engine crash inside a game now recovers by itself within a second instead of leaving the game's physics frozen (objects stuck in place, collisions dead) until the player reloads the page.
- Older worlds get their object sizes, attachment sockets, and model parts filled in way more reliably now — the game figures them out right in a player's browser using the same access that already renders the models, instead of a server that sometimes couldn't reach them.
- Sprites' sizes, ground anchors, and collision shapes stay perfectly consistent for everyone in a room, and load a bit faster on return visits.
- When a physics shape truly can't load (broken or removed model), Savi now gets one clear message about it instead of the engine quietly retrying forever.
- Grass and decorations no longer grow-shrink-grow repeatedly while a world first loads — the grow-in now plays exactly once per reveal, and far terrain streaming in never re-grows the field around you.
- Timers set with
runInSeconds/runInTicksno longer vanish when a player alt-tabs or reconnects — they hold and fire as soon as that player is back. Timers set by a player who then leaves still end with their tab: for deadlines that must survive that, use spawnlifetimeor a target tick in state. - Big built worlds got dramatically faster: the engine's per-tick bookkeeping for object hierarchies, world hashing, and script writes now scales with what CHANGED instead of how big your world is — a 7,000-object world that was spending its entire frame budget on bookkeeping (and freezing ~150ms every time a script wrote something) now pays almost nothing for the same edits.
- First-person held items are real now: attach a gun, tool, or hands to the camera (
feetPosition: { attach: "camera" }) and it rides the view with zero lag — full 3D models and meshes, not just sprites. Addmaterial: { depthTest: false }(models honor it now too) and the held item never clips into walls. Savi knows the whole recipe: aim-down-sights, bob and sway, per-player viewmodels. - "Press E" prompts stop haunting you: interact prompts hide when their object is invisible, gone, or already in your hands — no more permanent "Take" prompt floating on the gun you're holding.
- Material scripts that displace a surface (mountain relief, painted planets) can now read the surface normal while doing it — those looks compile and draw instead of falling back to a bare white shape.
- When a look transition can't fade (scripted looks snap by design), Savi is now told at the push — with the recipe for doing the fade inside the script — instead of promising you a smooth dissolve that hard-snapped.
- Saving a script edit no longer freezes the room: the new version boots in the background while the game keeps running, then swaps in an instant.
- Savi's changes reach your game much more reliably in singleplayer: rooms with no tab open run the change on the server, a hidden tab answers honestly in ~2 seconds instead of stalling Savi's turn for 20, and work a hidden tab can't do reroutes to the server instead of failing.
- A game that can't finish joining now fails fast and loud instead of holding you on a silent black screen forever.
- Music and sound generation that hits your hourly budget now waits politely and resumes when the window lifts — and Savi is told exactly which sound is capped — instead of that audio silently dying for the rest of the session.
- Destructible worlds keep their damage across script saves: geometry your scripts carved or changed at runtime no longer snaps back to pristine while the collision still remembers every crater.
- When an image or model is blocked by content policy, you and Savi learn immediately that it was rejected (and why) instead of watching a fake "still generating…" countdown for something that was never coming — only a reword can fix it, and now Savi knows that.
- Way fewer duplicate error alerts while you build: one broken script is one report (re-armed when Savi actually fixes it, not on a timer), and a script hammering a missing object logs once a minute instead of tens of thousands of times.
- Sprites no longer vanish for the rest of the session after you tab away: stuck texture loads time out and retry, failed GPU work re-tries itself, and returning to the tab revives anything that broke while you were gone.
- When the physics engine itself crashes, the errors now say so — instead of blaming your game's scripts and sending Savi chasing a bug that doesn't exist. You and Savi both hear about it honestly, and a reload cures it.
- Flat painted ground is a real look now: terrain with a tint and no texture stops warning forever about a "missing texture" you never wanted in the first place.
- Multiplayer places no longer wait on a player who never finished loading while a fully-loaded player waits.
- Savi learned to carry run state (inventory, dice, boarding passes) THROUGH place transitions the reliable way — seeded on the travel itself — instead of passing it through storage, which can lose it at the boundary.
- Dense top-down and 2.5D worlds with lots of depth-sorted sprites (
ySort) run dramatically faster — hundreds of trees, bushes, and props that used to each cost their own draw now share batches, with pixel-identical layering (soft-alphacutout: falsesprites keep their old per-sprite path, so their layering is unchanged too). ySorton ordinary sprites is now free: give it to everything on the interleaving layer without a performance tax.- Fast-paced worlds that spawn lots of physics props (bombs, projectiles, debris) no longer slowly lose their visual effects: entities the room silently dropped used to linger invisibly and eat effect capacity until explosions just stopped rendering — now they clean themselves up within seconds, effects included.
- A model that genuinely has no collision shape now tells Savi so once, clearly — instead of the engine silently re-asking forever and slowing down every other asset load in your world.
- Physics objects no longer twitch while rolling after bumps — a rolling ball or tumbling cube keeps its spin through network corrections instead of freezing and jerking.
- Savi now gets a log when a squash amount is out of range instead of silence.
- Savi's script edits now reliably wake up in your world — including worlds nobody has open — instead of occasionally sitting inert until a reboot.
- Saving a script edit can no longer kick everyone out of the room: one save is one seamless background swap, even when several update signals race.
- Mouse-look games with on-screen HUD panels no longer trap your cursor: click the game world and you're back to looking around, with the panel still on screen. Real menus and dialogs keep the cursor until you close them, like always.
- Savi now gets an accurate explanation when event handlers set up while spawning an object don't stick — the error tells her exactly where to move them, so she fixes it on the first try instead of being pointed back at what she already did.
- Panels you've already clicked past no longer flicker the cursor back when their UI re-renders — the engine now recognizes a re-rendered panel by its
ideven when the re-render rebuilds the element. - Night scenes and colored atmospheres finally show the color you authored: a deep navy vignette is deep navy, a 9% haze reads as 9% — dark looks stop washing out into a pale veil.
- Multiplayer places no longer freeze up permanently when one player's connection quietly breaks one way — the room notices within seconds and keeps going on its own, instead of needing Savi to restart the room.
- Equipment and body rigs are one declaration now: give any object tree
parent: "player"and EVERY player in the room wears their own copy — swords, boards, flashlights, full composed rigs — with no pooling scripts, no ownership wrangling, and no more "works with one player, vanishes with two." - Fixed a loading screen that could stay stuck at "Starting game…" over a game that was actually running — anyone hitting it had to be told their world was fine; now the curtain lifts as soon as the game is drawn and its content is loaded.
- Fixed a bug where games with a custom camera and no camera script (common in UI/card games) got stuck on "Starting game…" forever. They load normally now.
- Custom player models set from scripts finally obey your animations: the default avatar's built-in walk/run no longer hijacks a model your script dressed and animated — your idle/walk/run play the moment your script writes them.
- Savi's singleplayer fixes land even when your tab is closed or hidden: her script runs on the server instead of failing with "no client" — the biggest remaining class of "Savi said she fixed it but nothing happened" in solo worlds.
- Savi's teaching got truer in the corners: she now knows spawned objects must live in a resident place to replicate, that one building is one place (no more place-per-floor), how to stamp bone-mounted equipment on every player, and to let YOU be the judge of whether a fix worked.
- Tilemap tiles can animate now: stack frames vertically in a tileset atlas and set
tilesetFrames+tilesetFps— shimmering water, flickering torches, whole layers playing in lockstep. Worlds that don't use it render exactly as before. - Deleting a state key finally sticks:
patchState({ done: undefined })survives restarts, and the newapi.deleteState("cells.3,4")deletes nested keys — no more stringified-doc or tombstone workarounds for "clear". - Bulk property writes (
batchSetObjectProperties,setPositions) made in persistent scripts now save like single property writes instead of silently reverting on reload. - Cursor-followers stop freezing during movement — the pointer ray now always tracks the camera you see. Cursor rings, placement ghosts, and aim markers stay glued to your pointer while you move.
- When an art or voice budget runs out mid-build, Savi now learns the real time generation resumes — no more silently missing sprites, and no more "back in an hour" promises over a parked daily budget.
- Terrain with small repeating ground textures stops reading as an obvious grid from above: tight repeats now get the natural per-tile variation they were always meant to have, while larger hand-authored patterns (8m and up) keep their exact look. Cliff sides are unchanged.
- Passing a long digits-only string to a drawn-art texture script no longer scrambles it into a giant number — encoded pixel payloads arrive exactly as written, no letter-prefix workaround needed.
- Sound range finally means what it says: give an ambient sound a
maxDistanceand it fades out smoothly and goes fully silent at that distance, instead of carrying across the whole map.playSoundcan take amaxDistancetoo. api.getInputRay(input)now returns exactly the ray through the pixel the player saw — cursor-following objects (rings, placement ghosts, aim markers) no longer lag or land offset from the cursor while the character is moving.- Mouse button releases can no longer get lost under heavy pointer movement: a short press during fast mouse motion releases exactly when the player lets go (held actions stop,
keyup-pulsed actions fire). - Fixed a multiplayer bug where every light in the room could flicker off and back on (about a fifth of a second, sometimes twice in a row) while someone was editing the game. Spec updates that needed a full refresh used to rebuild the player's whole world; now they refresh just the game spec, invisibly.
- Rays now hit what players see:
api.raycastintersects visible sprites by default — paper enemies, sprite tiles, and decor are targetable without adding physics bodies. Billboarded sprites are hittable from every direction, exactly like they're visible from every direction. Pass{ includeSprites: false }if a ray should only see physics colliders. - Fixed billboard sprite picking testing a quad mirrored below the sprite's feet.
- Voxel edits no longer flicker back to the old state when the world is busy: placing or clearing blocks next to active automata (flowing water, busy zoo ponds) used to show your edit for a frame, revert it for about a third of a second, then re-apply it. Your edits now stick the first time.
- Player sprites keep the size your scripts give them: wearing a skin with an explicit
sprite.sizeno longer snaps to the artwork's minted height when the engine's sprite metadata arrives (the "my character grew mid-walk" bug). Skins worn without a size still auto-size from the asset's declared world height — including when a player jumps straight from an explicitly-sized skin into an auto-sized one.