Skip to content

v0.7.1

Choose a tag to compare

@github-actions github-actions released this 14 Sep 11:12
· 2 commits to main since this release

Six days since v0.7.0: 770 commits that touch the engine, the editor or the demos, out of 2,259 in total.

This release has two themes. The first is identity that outlives its owner. koota reuses entity ids, so a respawned entity could pick up a destroyed entity's particles, audio voice, UI state, screen bounds or 3D pick target. Every per-entity cache was moved onto a single shape that checks the entity is still alive. The second is agent tooling that fails loudly. The MCP tools stopped turning an unknown input into a plausible action, and stopped reporting a refusal as a success.

Dependencies

  • three.js stays at 0.184.0. r185 black-screens iOS on the first launch after a clean install. The package peer range is now >=0.183.0 <0.185.0, and a test enforces it.
  • PixiJS and Rapier are unchanged for this release.
  • Security: all 10 open Dependabot alerts are cleared (sharp, js-yaml, vitest, and hono in both MCP servers).

⚠️ Upgrading from 0.7.0

  • GameDefinition.UIComponent is removed. The default game UI layer always mounts.
  • The capacitor-litert-lm plugin is removed, together with @mediapipe/tasks-genai. The packaged editor's CSP no longer allows remote origins in script-src / worker-src.
  • OTA publishing now deletes old bundle versions beyond ota.retainVersions (default 5). It always keeps the live version and anything under an hour old. Publishing also needs a git checkout and refuses a dirty tree.
  • UI actions: a param that arrives as '' is now treated as absent. Built-in engine actions report a refusal as ok:false instead of dispatched:true.
  • Scene load waits for Rapier and for sprite-animation, rig, animset and particle definitions, so the first frame is posed and has physics. The cost: loading takes longer in scenes that use them (about 130–175 ms more for physics on a Galaxy A23).
  • Build failures: a failed icon or splash generation now fails the build instead of shipping stale art.
  • Listener errors: an exception thrown by an engine listener is caught and reported instead of propagating.
  • Crashlytics: journalError now reports to Crashlytics in every build.
  • findEntity is typed (Entity | null), so code that leaned on it being any may need type fixes.
  • Packaged editor profile: the profile moved to a per-install, per-project folder. Editor settings such as the CDP opt-out, ports and tokens are carried over.
  • Updates: "Check for Updates" now asks before downloading.

✨ New

  • Reserved edge bands: mark a strip such as an ad banner with UIAnchor.reservesEdge. A dialog root marked clearsReservedEdges then stays clear of it and of the safe area.
  • Adaptive design height on Canvas2D (maxReferenceHeight, opt-in): tall phones use the extra vertical space instead of letterboxing.
  • UIElement.minTapSize enlarges a control's tap zone without moving its artwork. Real interactive content underneath still wins.
  • GTAO cost controls: AmbientOcclusionPostFX.resolutionScale and samples are authorable. On a Galaxy S22, scale 0.5 took postfx-demo from 28 to 60 fps.
  • UI overflow warning: in editor and debug builds, text that paints outside its box is reported. It appears as a [UIOverflow] console warning, in the journal and in diagnose.
  • refuseAction(): a UIAction handler can refuse, and dispatch_action reports it.
  • New engine.director action: play, pause, seek and change the speed of a cutscene from UI bindings.
  • OTA:
    • publish a shell's sub-games from the editor (Project Settings → OTA → Sub-games) or from MCP;
    • each manifest records the commit that built it;
    • a corrupt embedded manifest is reported instead of being treated as missing.
  • Playable ads:
    • asset-keep.json takes per-target playable keep/drop rules;
    • the end card is the call to action;
    • the time cap starts when the ad is viewable.
  • New engine APIs:
    • measureText2D
    • the ScreenBand layout solver
    • resolveCanvas2DHost
    • ensurePhysicsReady
    • entryIndexOf
    • testing helpers: tapTargetFloor, inOrder, scratchDir
  • Early monetisation modules, promoted from a shipping game and still evolving:
    • the store shelf (ShelfSession)
    • a daily calendar
    • a login bonus
    • the capacitor-applovin-max plugin
  • Demos: all six demos have an app icon.

🐛 Fixes

  • 2D text was invisible on every iOS 16 device. The MTSDF atlas was decoded premultiplied. Verified on an iPhone 8.
  • Recycled entity ids: a respawned entity no longer inherits a destroyed entity's state. This covered particles, audio voices, skinned clones, text animation, UI DOM and hooks, prefab override marks, physics controls, video decoders, timeline registries, screen bounds and 3D picking.
  • Physics from the first tick: Play and step used to run their first ticks with no 2D physics while Rapier's WASM was still loading.
  • No pre-pose flash: the first frame after a scene load is posed.
  • 2D textures:
    • the "destroyed while still bound" WebGPU errors are gone;
    • textures survive a scene swap instead of being destroyed and decoded again;
    • a wedged 2D canvas recovers;
    • a re-imported sprite, font, model or audio file shows its new bytes in the editor.
  • Scene swaps survive a throwing listener, instead of aborting halfway.
  • Packaged editor:
    • "Check for Updates" always answers, including when an update exists;
    • "Restart Now" no longer races the macOS updater;
    • a startup failure exits (and leaves a log) instead of hanging;
    • main-process dialogs no longer freeze the app.
  • Preview and undo safety:
    • saving inside a preview no longer loses one of its writes;
    • undo, Play and scene edits are refused or scoped correctly during scrubbing and preview restores;
    • a scene or prefab reload that arrives during Play is deferred to Stop instead of being dropped;
    • editing a .prefab.json outside the editor now reloads it.
  • Scene view:
    • the UI preview picks the 2D entity under the cursor;
    • 2D gizmo, group and vertex drags released outside the canvas commit;
    • a lost graphics context recovers instead of leaving the panel black;
    • collider-only view mode announces itself, and the Type filter badge names the active types.
  • Editor panels:
    • Sprite and Nine-Slice editors: resize follows the pointer and no longer collapses a slice.
    • Physics Layers: the matrix stays symmetric after adding a layer.
    • Undo history: undo labels name the entity.
    • Assets and Hierarchy: re-selecting reveals the row again.
    • Running game: it no longer steals presses on editor panels.
    • Skin weight painting and 2D edits reach the Game view while stopped.
    • .meta.json: write failures are shown instead of swallowed.
    • Asset move/rename: reference repair no longer skips when a runtime tab is open.
  • UI runtime:
    • a single-axis scroll view no longer traps swipes on the other axis;
    • a quick double page step moves two pages;
    • pooled rows read nested prefab roots correctly, and refuse a vw/vh-sized root instead of guessing.
  • Timeline:
    • a seek while paused re-poses the scene;
    • seeking onto the end fires the end event once;
    • a slaved sub-director refuses transport commands instead of pretending;
    • an un-slaved sub-director restarts correctly.
  • Data robustness:
    • keys such as constructor or __proto__ in scene or config data no longer crash anything or pollute objects;
    • audio.setBusVolume checks the bus name before writing.
  • Builds:
    • the CLI native build generates icons from project.config.json;
    • an empty iconSource falls back to the bundled icon;
    • the iOS heal strips an unused Facebook SDK from Firebase Auth;
    • opening a project waits for a build that holds it.
  • Crash reporting: on iOS, JavaScript errors reach Crashlytics with their message, and each report gets its own grouping.
  • Toolchain: removing tools refuses a junctioned folder instead of reporting it removed, and works after a toolchain folder rename.
  • Demos: forest-camp's D-pad buttons no longer overlap on notched phones, and its progress bars are the right size.

⚡ Performance

  • Boot: the shader prewarm skips work that does nothing under a post-FX stack, cutting its main-thread stall by a third on a Galaxy A23 (289 → 193 ms).
  • GTAO: see the cost controls under New.
  • Level reloads: a scene swap no longer destroys and re-decodes 2D textures.

🤖 Claude Code / MCP

  • New modoki_wait_for: waits until an editor, entity, console or chrome condition holds, instead of a fixed sleep. It also works as a modoki_batch step. This is the only new tool; none were renamed or removed.
  • Editor chrome is readable and aimable by label:
    • modoki_handles {editor:'chrome'} reads live inputs, checkboxes, tabs and mixed multi-select state;
    • tap, drag, pointer, hover, scroll and focus accept a label aim.
  • iOS over USB: device_connect {useUsb:true}, through go-ios.
  • Errors say what happened:
    • a refusal carries its real error code, not a generic REFUSED_BY_OP or a timeout that looks like a dead editor;
    • an unknown value is refused with the valid options. This covers mouse buttons, pointer actions, modifiers, key names and journal levels;
    • modoki_eval reports op refusals correctly.
  • Quieter correctness:
    • modoki_type_text can type a newline;
    • modoki_dnd reports asset-editor drops that did land;
    • modoki.import loads the app's own module instance;
    • get_scene_state reports guid:null for guid-less entities, and a new scene's starter entities get real GUIDs;
    • scene-mutate and asset-write refuse when they would destroy unsaved editor changes.
  • Device leases: ending a lease always stops WebDriverAgent, and one holder can no longer release another's phone.

Full Changelog: v0.7.0...v0.7.1