Releases / v0.117.0-rc16

v0.117.0-rc16 Whole Worlds

2026-10-26

Everything in rc12, plus a profiler that names what a slow frame spent its time on, terrain shadows that update without stalling, terrain answers a game can trust, cheaper vectors, and spawns a game can spread over frames.

Find what a slow frame did

  • perf.frames(n) keeps the last 300 frames exactly, each with its buckets, parts, scripts and engine calls, instead of a smoothed average.
  • Physics is broken into stages (broadphase, contact with the world, sweeps, joints, pairs, sleep), and perf.bodies(n) lists the costliest bodies.
  • perf.sampleScripts(true) samples running scripts and names the hottest lines of each frame and each hitch, including the line whose engine call was slow. It slows tight loops while on, so it is off until asked.
  • perf.scripts() rows show the engine time each script spent in rays and casts.
  • perf.hitchThreshold(ms) sets what counts as a hitch (50 ms by default).
  • perf.pacing() says when frames are held by the display, the compositor or a frame cap rather than by the game.
  • Time that used to read as untimed is named: waits outside the frame, the frame cap, scene loads and physics rebuilds. A built game's scene render now counts as render; before, all of it read as untimed.
  • Render is split into culling, instancing and passes.

Big craft come to rest

A large craft lying on the ground now falls asleep within about a second of settling. Before, a wide craft kept reading as moving by a few centimetres a second and never slept, so a 1,000-part craft let go beside a base cost over 100 ms of physics a frame for as long as it lay there; asleep, it costs well under a millisecond. Everything moves exactly as it did until the moment it sleeps. A sleeping craft checks the ground under it a little each step instead of all at once each second, and something must come within a few centimetres of it to wake it.

Physics that cannot fall behind itself

Project Settings → Game now shows Tick overload and a new Catch-up budget: the most milliseconds of fixed ticks one frame may run. With a budget set, a frame that cannot fit its banked ticks drops the rest instead of running them all and falling further behind. Unset, nothing changes. A networked game always catches up. See When the ticks get expensive in the physics docs for what a game gives up.

Terrain shadows without the stall

The terrain shadow volume is now updated in place: a world, rock or moon that arrives adds only its own shadow, a dig uploads only the box it changed, and each frame uploads a bounded amount. A landing world no longer stalls the frame it arrives on, and nothing loses its shadow while the new one is laid. Edits at two places far apart no longer upload everything between them, and edits to two terrains in one frame both reach the screen.

Terrain a game can trust

  • terrain.ready(x, y, z, r) says whether the ground there is made and final. Until it is, terrain.query may answer from a coarse stand-in or read open air where ground has not been made yet.
  • terrain.raycast(origin, dir, maxDist) finds the first surface along a ray from the terrain itself, and answers nil, "unknown" where the ground is not made yet instead of passing through it.
  • terrain.prepare(x, y, z, r) makes stand-in ground exact in the background, ahead of a game that will plan from it.
  • terrain.paint and terrain.paintTexture return a receipt, 0 when the edit queue was full. terrain.capacity() says how much room it has, and perf.counts().terrainDropped counts refused edits.
  • The time a frame spends on terrain edits is split into landing, applying and what follows, and an edit that makes ground on the frame says so once.

Scripts

  • Reading .x, .y or .z from a vector is over ten times cheaper, and vector maths between vectors runs without leaving the script.
  • node:child(id) finds a child by id in one step, and node:childrenGeneration() changes whenever a node's children change, so a script can keep a cached list and know when it is stale.
  • Spawning many prefabs with callbacks costs a fraction of what it did. spawnBudget(ms) spreads a big build over frames, spawnPending() counts what is left, and spawnDone(fn) is called when all of it has landed.

Upgrading

Projects upgrade themselves; nothing to do. What upgrading cannot change for you:

  • A vector (vec3) is now a table: type(v) returns "table", not "userdata", and pairs(v) lists its x, y and z. A script that used type(x) == "table" to tell an options table from a vector can test getmetatable(x) == getmetatable(vec3(0, 0, 0)) instead.

Floptle Hub

Linux x86_64 10.7 MB Download → sha256 17261786a3c8540058c006ea8ccb780455cff9b2efea39a63d17f65776d61127
macOS Apple Silicon 7.4 MB Download → sha256 f6b216b1e05b880e0d3c83769c5ee1cb1b401319e8ef36b5f7ead48ea7be233c
macOS Intel 8.0 MB Download → sha256 7ac3d4b97755b3c6a937fae8ec2ee7e6e17fefb2221770e5ef5229336465ba49
Windows x86_64 9.1 MB Download → sha256 cbb248ac0e3d66c58018f25dee46e5b278981b4e61ccf3349562a3179e0527f7

Engine

Linux x86_64 58.1 MB Download → sha256 8c2525fbc9e7ac1180d58debdfde1e994b5634756c777fdb78ce0c792fc8551c
macOS Apple Silicon 45.6 MB Download → sha256 ca2b5cb2e5116d864219a6b1bf0118749a894573461358c1afa046b6f666a8f0
macOS Intel 49.1 MB Download → sha256 ad6ba9eca493754bd2121318dbce00a0c3dea26e8a0d9add999117f6b1ed0098
web 5.5 MB Download → sha256 2bf4b482b65b3dd1d07a9b56954999d3764d27655965dffcb41753d02b852e11
Windows x86_64 55.4 MB Download → sha256 4620e2922fd102e36ec555e9157ae065fca77fdb324741df160b0514e5154378

The binaries are not signed yet. On macOS, right-click the app and pick Open the first time. On Windows, if SmartScreen appears, pick More info then Run anyway.