feat(bundle): ship a game as a macOS .app, with a splash it controls
`ludic build` produces a program. Double-clicked it opens a Terminal window, it wears the generic executable icon, it calls itself whatever the file is called, and it carries none of its assets. `ludic bundle` produces an application. Everything it needs is in package.ludic, so the command takes no arguments: an Info.plist and PkgInfo from `app` lines, an .icns built by sips and iconutil at all ten sizes macOS asks for from a single source PNG, the asset pack in Contents/Resources, and an ad-hoc signature - which is not optional on Apple silicon, where an unsigned binary is killed rather than warned about. The bundle identifier falls back to the package path reversed, so a project that never thinks about it still gets a defensible one instead of two apps sharing a key Launch Services hangs the Dock, saved state and permissions off. A bundled game is moved to ~/Library/Application Support/<name> before main, because Finder starts a .app with its working directory at "/" where no save could ever be written. Reads come out of the pack, writes land somewhere real and per-user, and the game's save code needs no change and no platform knowledge. The splash is the other half of looking like an application. A game that loads 165 MB spends a visible moment doing it with nothing on screen, which from the outside is indistinguishable from a launch that failed. splash_show puts a borderless window up from the same constructor that mounts the pack - before main, so it appears while the process is still starting rather than after the slow part it exists to cover - and reads the artwork out of the pack like any other asset. It turns the run loop enough times to be mapped and composited there and then; once composited the backing store survives a busy main thread, so it stays up for the whole load. Nothing hides it automatically. Only the game knows when its first real frame is ready, and a splash that vanishes before that leaves the same black gap it was covering, so the game calls App.splash_hide(). Headless there is no splash and the call lowers to nothing. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
parent
ce5bf0fe0e
commit
be74b4de6f
14 changed files with 34667 additions and 33621 deletions
12
changes/asset-packs.md
Normal file
12
changes/asset-packs.md
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
bump: minor
|
||||
type: feat
|
||||
**Asset packs.** `ludic pack` writes every asset a game opens into one `.lpak`
|
||||
beside the binary, and the runtime mounts it before `main`. Nothing about how a
|
||||
game is written changes: the pack is spliced in at `file_open`, the one place
|
||||
every asset comes through, so `gltf_load`, `tex_load`, `Audio.load`,
|
||||
`Fs.read_text` and the renderer's own shader loads all find it without knowing
|
||||
it exists. `Fs.exists` and `Fs.size` consult the packs too. Entries are stored
|
||||
rather than compressed and the pack is `mmap`'d, so 165 MB of terrain costs one
|
||||
syscall at startup and pages in only what is touched. Several packs can be
|
||||
mounted in order, and a later one shadows an earlier one - which is how a patch
|
||||
replaces individual files without rewriting the base pack. See `docs/SHIPPING.md`.
|
||||
9
changes/boot-splash.md
Normal file
9
changes/boot-splash.md
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
bump: minor
|
||||
type: feat
|
||||
**A boot splash**, customised by the game. `app splash` in `package.ludic` names
|
||||
the artwork and `app splash_bg` the colour behind it; the runtime raises a
|
||||
borderless window from a constructor that runs before `main`, reading the image
|
||||
out of the asset pack, so it is on screen while the process is still starting
|
||||
rather than after the slow part it exists to cover. Nothing hides it
|
||||
automatically - only the game knows when its first real frame is ready, so the
|
||||
game calls `App.splash_hide()`.
|
||||
9
changes/macos-bundle.md
Normal file
9
changes/macos-bundle.md
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
bump: minor
|
||||
type: feat
|
||||
**`ludic bundle`** turns a built game into a real macOS `.app`: `Info.plist` and
|
||||
`PkgInfo` from the manifest, an `.icns` built from one source PNG at every size
|
||||
macOS asks for, the asset pack in `Contents/Resources`, and an ad-hoc signature
|
||||
so it launches on Apple silicon. Everything comes from `app` lines in
|
||||
`package.ludic`, so the command takes no arguments. A bundled game is also moved
|
||||
to `~/Library/Application Support/<name>` at startup, because Finder starts a
|
||||
`.app` with its working directory at `/` where no save could ever be written.
|
||||
Loading…
Add table
Add a link
Reference in a new issue