Releases / v0.99.0

v0.99.0 Ship It

2026-09-26 Latest

Signing in to Floptle stays signed in, music starts without a stutter, a game can show pictures it downloads (a player's profile picture among them), and a dedicated server goes from your project to Floptle Cloud in one command.

Signing in stays signed in

A Floptle sign-in, in the Hub or in a game, was kept only while the program ran: close it, and the next launch asked you to sign in again. Games also never saw the Hub's sign-in, although they were meant to. The sign-in is now kept in your system's own password store (Keychain on macOS, Credential Manager on Windows, the Secret Service keyring on Linux), so it survives a restart and the Hub and your games share it.

Sign in once more after updating; from then on it sticks.

Test runs play signed out

Now that a sign-in lasts, floptle run, floptle shot and floptle exec start signed out, so a test that presses a submit button never writes to your real account. cloud.* reads still work. Add --signed-in when a test needs your account, and its uploads are then real. Each run says which it is on its first line.

A new music track no longer freezes the game

The first time a sound played, its whole file was decoded on the spot. That is about a millisecond for a gunshot, and a tenth to a fifth of a second for a two-minute music track: a visible hitch every time the playlist moved on. Sounds are now read in the background, and the frame never waits.

A sound asked for before its file is read waits a moment, then starts. Meanwhile it already reads as playing, from 0 seconds, and sound:isLoading() (and node:sound():isLoading()) is true. Seeking, pausing, volume and stop() given in that moment all take effect when it starts. When a sound has to start on the exact frame it is asked for, read it in earlier, on a menu or a loading screen:

lua
audio.preload({ "audio/hit", "music/level1.ogg" }, function(failed)
  -- every clip is in; `failed` lists any that could not load
end)

assets.preload takes sound files too, beside models, with one callback for both.

Decoded audio is no longer kept for the whole session either. Clips nothing is playing are kept while they fit in 64 MB, and the least recently played goes first, so a long playlist no longer grows memory by hundreds of megabytes. A preloaded clip is kept until its first play.

Pictures from the internet

A game can turn a picture it downloads into a texture, and use it anywhere a texture goes: draw.quad, a UI image, a material.

lua
assets.textureFromUrl(url, function(tex, err)
  if tex then ui.make(row, { "image", w = 32, h = 32, texture = tex, radius = 16 }) end
end)

A UI image with a radius of half its size draws round, which is how profile pictures usually look. assets.textureFromBytes(bytes, cb) does the same with bytes you already have, and assets.release(tex) lets a picture go.

The bytes are only ever read as pixels. PNG, JPEG and WebP are accepted, recognised by the file's own contents rather than its name. Anything else, or a picture over 4096 pixels a side, is refused with the reason. A URL already loaded this session is not downloaded again.

http.get and http.post now carry bytes both ways, so a downloaded file arrives whole in res.body. Before, any picture failed on its first byte that was not text.

Floptle Cloud, read as your game

Some things a game shows need no player signed in: another player's picture, the settings you publish from your game's page, a public leaderboard on the title screen. cloud.* reads those as your game, with the key your project already carries (⚙ Settings ▸ Networked). Your scripts never see the key.

lua
cloud.avatar(net.identity(peer).id, 64, function(tex, err)
  -- err is "no_picture" when the player has none: draw your own stand-in
end)
cloud.config(function(config) motd = config.motd end)
cloud.get("/games/" .. cloud.game() .. "/rank/laps", function(res) end)

Files your players store on Floptle Cloud travel as raw bytes both ways through account.*, so a replay or a picture a player uploaded comes back exactly as it went up, ready for assets.textureFromBytes.

Ship a dedicated server in one command

floptle ship <PROJECT>

floptle ship makes the dedicated-server bundle and uploads it to your game's page on fopull.com, signed in as you in the Hub. Deploying it is then a click on that page. The upload goes in pieces, so a bundle of any size gets there, and a dropped connection or an expired upload link is recovered without you doing anything. If it is stopped part-way, run the same command again: while the project is unchanged it carries on from where it stopped.

The editor does the same from ⚙ Settings ▸ Networked ▸ Ship a server build, with its progress in the Console.

A restarted server keeps its code and its players

A dedicated server that restarted could come back on a different six-character code while the old connection was still being cleaned up, so players holding the old code could not join. A restarted server now takes its own lobby back, players and all.

A server that came back into a lobby its players were still waiting in did not learn they were there, so it never sent them anything. It does now.

Managed relays are verified

Floptle Cloud's relays have presented a verified certificate for some time. Until now, a connection whose certificate did not check out went ahead anyway, with a warning. It is now refused, with the reason, so nobody can stand in the middle of a managed session.

For editor packages

ed.camera() describes the whole Scene view as it is drawn: up, right, near, far, ortho, the view's size in pixels and its aspect, fovYDeg (or orthoHeight in 2D), and frustum. The Scene view is usually off to one side of the window, so frustum gives its exact shape.

Upgrading

Sign in to Floptle once more, in the Hub or a game; that sign-in is kept from now on. Nothing else to change. Three things behave differently:

  • A sound's first play starts a frame or more after the call instead of freezing the game. If that matters, audio.preload it.
  • A game that polls sound:isPlaying() to move a playlist on sees true while the next track loads, as it should.
  • A game connecting to a managed relay whose certificate does not verify is now refused instead of warned.
  • floptle run, shot and exec play signed out unless given --signed-in.

The dedicated-server fixes need both halves on this version: the server you ship, and the relay it registers with, which Floptle Cloud updates.

Floptle Hub

Linux x86_64 9.0 MB Download → sha256 bf74f2d85b0cdbcbbbb7634d51472dfb82e273e7830e07f68548d69bdc612253
macOS Apple Silicon 5.9 MB Download → sha256 ec4314e2dfdb2acd9829c71b43107666e08349358a053917889d16b6355cfd5d
macOS Intel 6.4 MB Download → sha256 c77c1377be8806ff125fa6373961c8638c77f99ea2d53a068ec24dbc69d9c5cd
Windows x86_64 7.3 MB Download → sha256 1cd10cdafdf76294bd79b5b0afa729e238ce796926df6f0b6ecbba21856b5ba2

Engine

Linux x86_64 36.6 MB Download → sha256 ac06ec430ed4aa79e184f3aaac576bf48cc02507c6f8e3d77774e2fe8c4762b7
macOS Apple Silicon 28.1 MB Download → sha256 27f4e73573ef87b917caa7d80a584d66a3fae716eccbaa33653aa09f9c38aee4
macOS Intel 30.4 MB Download → sha256 3181709778448a0780416e12f8d5431cd165fed182e51d6fc259e665ad26dc68
web 4.4 MB Download → sha256 8add2258cc504720820aba44eb80aa4863a4287a8c15b1a81ceb46988d3e1d1b
Windows x86_64 34.3 MB Download → sha256 6687288d5703d79f193d578c060128d7a4bb3d4b2a927a8dcf2b2afddd3e71f2

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.