> For the complete documentation index, see [llms.txt](https://docs.allout.game/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.allout.game/changelog/readme.md).

# Changelog

New updates and improvements

{% updates format="full" %}
{% update date="2026-09-02" %}

## Protocol 48 - In development

* Tutorials now show larger, noninteractive instructions below the top HUD. Text-only `Tutorial_Step.message` / C# `TutorialStep.Message` and legacy `ReadText` steps, Continue/Dismiss controls, and their APIs have been removed. Attach short instructions to gameplay action steps instead.
* Named player inventories: `Items.create_player_inventory(player, key, capacity)` / C# `Inventory.CreatePlayerInventory(player, key, capacity)` must be called during that player's `ao_start` / `Awake`. They restore synchronously, save automatically, and are destroyed with the player. Repeated calls during startup return the existing inventory; retain it for later use.
* Item-reference APIs are now named CSL `Save.save_item_reference` / `Save.get_item_reference` and C# `Save.SaveItemReference` / `Save.GetItemReference`. They and item fields in Save JSON support all persistent player inventories. Transfers to another inventory invalidate references, including transfers within the same player. Existing saved references remain readable. Create named inventories before resolving saved items.
* Added `Items.mark_item_dirty(item)` for saving direct edits to serialized CSL item fields.
* Player inventory spawn data now includes named inventories. Clients and servers must agree on engine memory version for both CSL and C#.

<details>

<summary>Multiplayer</summary>

* Typed text now reaches the server and survives resimulation
  * Keyboard and IME text travels with the other per-frame inputs, so UIDoc `<input>` fields, chat, and every `UI.text_input` widget hold the same value on the server and in every client resim
  * Before this, a text field bound to replicated UI state was overwritten by the server copy on the next resim, so typed characters were lost and `UI.uidoc_text_value` returned the empty or default string on the server
  * Text is capped at 64 bytes per frame; a longer paste is truncated on a UTF-8 boundary with a warning
  * Protocol 48 clients and servers cannot communicate with protocol 47 builds

</details>

<details>

<summary>Compatibility and Migration</summary>

* `Type_Info.printable_name` was removed to reduce the memory cost of runtime type information
  * Use `type_info.id` when a printable type name is needed
* `Inventory_Draw_Options.hotbar_item_count`, `columns`, `rows`, and `force_select_hotbar_index` now use `int` instead of `s32`
* Sprite renderer color is now consistently named `color`: the reflected/editor JSON field changed from `Sprite_Renderer.tint` to `Sprite_Renderer.color`, and C# `Sprite_Renderer.Tint` changed to `Sprite_Renderer.Color`
  * Existing serialized JSON using `tint` continues to load, but new JSON writes `color`; C# `Tint` remains as an obsolete compatibility alias
* `Spine_Instance.color_multiplier` is now `color`; the promoted field on CSL `Spine_Animator` follows the same name, and C# `SpineInstance.ColorMultiplier` is now `SpineInstance.Color`
  * Reflected JSON using `color_multiplier` continues to load; C# `ColorMultiplier` remains as an obsolete compatibility alias
* Renamed the `Entity.set_parent` argument from `keep_world_position` to `keep_world_transform`, since it preserves world-space position, rotation, and scale
  * C# uses `keepWorldTransform`, as does the editor `setParent` operation; the editor continues to accept `keepWorldPosition` and both legacy snake-case spellings

</details>

<details>

<summary>CSL Language and Compiler</summary>

* Dynamic arrays can now be created with compound literals, including runtime expressions and class field defaults
  * For example: `values: [..]int = {1, 2, 3}` or `return {seed, seed + 1}` from a procedure returning `[..]int`
  * Mutable class defaults receive independent backing storage for each instance
* Strings can now be concatenated with `+` and `+=`
* Floating-point literals may omit the leading zero, including in negative values such as `.52` and `-.52`
* Multiple values can now be assigned to existing destinations with syntax such as `route_target, route_valid = cinder_route(...)` or `a, b = b, a`
  * Use `_` to ignore an unwanted result
  * Every right-hand expression is evaluated left to right before destinations are resolved or written, so direct swaps behave as expected
* Taking a raw address with `&` now requires an `#unsafe` context; use `ref` for ordinary by-reference arguments
  * A single unbraced declaration after `#unsafe` remains in the surrounding scope and composes with declaration modifiers such as `using`
* Procedure literals can now capture enclosing parameters and local variables
  * Capturing procedure literals may be invoked immediately or passed directly as callbacks, but cannot be assigned to variables, returned, or otherwise stored
  * Unannotated procedure parameters may receive captures and can only be invoked or forwarded directly
  * Capturing and non-capturing values share the same procedure type and an explicit two-word procedure/environment representation
  * Mark a callback parameter `#no_captures` to store or return it; callers must pass a non-capturing procedure and keep persistent state in explicit userdata
  * Procedure values are no longer treated as pointer-sized values and cannot be cast directly; `#no_captures` contracts are also validated when calls enter CSL procedures
* Derived classes expose a read-only `base` field that views the same object as its immediate parent type
  * Use `base.method()` inside a derived method that shadows a parent method, or `value.base.method()` to select the parent method explicitly
  * CSL method calls are not virtual: lookup uses the receiver's static type, so calling a method through a base-typed value never selects a same-named method from the derived type
  * `base` is not reserved; a local declaration named `base` shadows the inherited field normally
* Added `ceil`, `floor`, and `round` overloads for `f32` and `f64`
  * Common scalar math, vector `dot` and `lerp`, angle conversion, and RNG mixing now compile directly to VM instructions; several helpers also gained `f64` overloads
  * Fixed the two-point `in_range(a, b, distance)` overload testing the wrong distance
* Fixed procedure calls incorrectly hiding compatible overloads declared in outer lexical scopes when a closer scope declared the same name
* Fixed class casts accepting unrelated types and silently reinterpreting their object handles
  * Base-to-derived casts now validate the concrete object type at runtime; derived-to-base casts remain free
* Fixed vector arithmetic such as `v2{1, 2} + v2{3, 4}` producing incorrect results when both operands were constant expressions
* Fixed overloaded and inherited component lifecycle methods sometimes not being registered as the component's active hook
* Improved compiler diagnostics for unsupported exponent literals, unresolved identifiers, missing declaration semicolons, misplaced `ref` and `defer`, and invalid member access on primitive types

</details>

<details>

<summary>Gameplay APIs and Runtime Fixes</summary>

* Added closure-friendly `Entity.add_component` and `Scene.instantiate` overloads whose initialization callbacks do not require explicit userdata
  * The callbacks run synchronously and may capture caller locals; `add_component` also gives its callback the concrete component type
* Added `has_freeze_reason`, `has_invisibility_reason`, `has_name_invisibility_reason`, `has_name_offset_reason`, `has_ghost_reason`, `has_disable_movement_input_reason`, and `has_joystick_disable_reason` to `Player_Base`
  * Every reason family also has a `has_any_*_reason()` query; emote blocks now have both `has_emote_block_reason(reason)` and `has_any_emote_block_reason()`
  * Player state reasons are counted rather than set-like; each add still requires one matching remove
* Added persistent inventory-item references through CSL `Save.save_item_reference` / `Save.get_item_reference` and C# `Save.SaveItemReference` / `Save.GetItemReference`
  * References survive slot rearrangement and become invalid when the item leaves the player's default inventory
  * CSL `Save.set_json` records can contain `Item_Instance` or derived item fields with the same persistent-reference semantics
  * `Item_Instance.entry_id_in_inventory` exposes the opaque inventory-scoped ID for diagnostics
* CSL `Save.set_int` and `Save.get_int` now preserve full `s64` values, and `Save.set_float` / `Save.get_float` provide convenience aliases for ordinary `float` values
* Added `Player.override_movement_input_for_next_step(input)`, including support for overriding movement with `{0, 0}`
  * Direct use of `Player.input_override` is soft-deprecated
* Added Spine placement APIs for querying bone position and local axes, along with `Texture_Asset.get_world_size()` for sizing attachment art
* Fixed `Items.draw_hotbar(...).selected_item` returning an invalid CSL class reference
* Inventory loading now rejects malformed types, invalid or duplicate slots, and inconsistent capacities more reliably
* Fixed custom CSL item types losing their concrete identity across script hotloads, and fixed persisted inventories being restored with the wrong CSL VM context
* Chat command names are now matched case-insensitively when no exact-case command exists, surrounding whitespace is ignored, and `Player` arguments support complete names containing digits, underscores, or quoted spaces
* Fixed text queued from CSL `ao_draw` callbacks sometimes not rendering

</details>

<details>

<summary>Editor and Iteration</summary>

* Project opening and Start Game are faster by preparing and publishing assets in parallel, overlapping script compilation with scene loading, and reusing cached scene packages and asset hashes
  * Unchanged C# projects reuse assemblies by content hash, and large scenes save incrementally without undo or redo invalidating the save cache
* Project opening now verifies that every preprocessed asset is published, and Start Game waits for pending publishing instead of launching with stale assets
  * Publish failures are shown beside the play controls with a **Try Again** action
* The editor now shows the active loading phase while opening a project or launching Start Game
* Added **File → Force Recompile Scripts** and **File → Clear Project Caches** recovery actions
  * Generated asset, scene, and compile caches are consolidated under the project's `.ao` directory and can be rebuilt from authoritative project sources
* Replacing an asset with a file whose timestamp is older or unchanged now triggers preprocessing and running-game asset hotload correctly
* Prefab edits now invalidate their directory-backed asset correctly and refresh linked instances in the open scene
* Editor-only Spine preview state and Box Collider cursor tracking no longer pollute scene undo state
  * Selecting a Box Collider no longer keeps the scene permanently dirty or prevents an undo snapshot from settling
* Deferred GPU resource destruction is drained safely when reloading an editor project

</details>

<details>

<summary>CSL Performance and Memory</summary>

* The compiler releases its syntax tree after producing executable code, substantially reducing retained memory for large projects and repeated hotloads
* Immutable runtime type information now lives outside networked game state and shares interned strings, reducing memory use and netsync work
* Fieldless classes, including CSL asset handles, no longer allocate unused payload storage for every instance

</details>
{% endupdate %}

{% update date="2026-08-24" %}

## Protocol 47 - August 24th, 2026

Protocol 47 adds state-preserving CSL code and asset hotloading, deterministic particle systems, rich-text UI, custom typed C# items, and expanded live-event APIs. It also improves editor workflows, compiler diagnostics, rendering performance, and runtime reliability.

<details>

<summary>Compatibility and Migration</summary>

\* C# component \`Update\`, \`LateUpdate\`, \`PredictUpdate\`, and \`PredictLateUpdate\` callbacks are now grouped by concrete component type instead of running in global component-creation order \* Do not rely on callback order between different component types \* \`Inventory\_Draw\_Options.default()\` is now hard-deprecated \* Use \`Inventory\_Draw\_Options.inventory\_default()\` for a full inventory or \`Inventory\_Draw\_Options.hotbar\_default()\` for the previous six-slot hotbar behavior \* Multi-return procedure signatures should now parenthesize their return types \* Use \`proc() -> (A, B)\`; the legacy \`proc() -> A, B\` form still compiles but reports a warning \* Particle-system emission and sizing now use intent-level configuration \* Replace \`spawn\_type\`, \`particle\_count\`, and \`emission\_rate\` with \`Particle\_Emission.burst(count)\` or \`Particle\_Emission.continuous(rate)\`; continuous slot capacity is derived automatically \* Replace \`half\_size\_over\_lifetime\` with full-extents \`size\_over\_lifetime\`, doubling existing values to preserve their visual dimensions \* A component's active \`desc\` is read-only; customize \`get\_desc()\` and pass the result to \`play()\` \* CSL GC-root ownership is now explicit \* \`new(T)\` is rejected when \`T\` is a \`#gc\_root\` type; use \`#alloc\_root(T)\` with a matching \`#free\_root\` \* \`#alloc\_root\`, \`#free\_root\`, \`#rootify\_object\`, and \`#unrootify\_object\` must be used from a \`#unsafe\` context \* Hotload migration requires unique global and procedure link IDs \* Ambiguous IDs now fail compilation and report both declaration or instantiation sites \* \`Entity.inverse\_model\_matrix\` is now calculated on demand \* Replace field reads such as \`entity.inverse\_model\_matrix\` with the method call \`entity.inverse\_model\_matrix()\` \* Added the dry-run-first \`tools/upgrade\_protocol47.py\` migration helper \* It can migrate unambiguous inventory draw defaults and, with a running editor MCP endpoint, directly assigned anonymous procedures that have link-ID collisions \* Pass \`--write\` to apply its proposed changes; Git-backed projects with dirty scripts are rejected unless explicitly allowed

</details>

<details>

<summary>CSL Hotloading and Live Development</summary>

* CSL edits can now hotload into open editor scenes, open prefabs, and running Start Game processes without restarting the session
  * Compatible globals, statics, class and component fields, strings, arrays, procedure values, player references, and component inheritance are migrated to the new program
  * Incompatible fields are reinitialized, removed classes become null, and removed component types require confirmation before their instances are destroyed
  * A compile failure leaves every scene on the previous program instead of applying a partial hotload
* Added the optional server-side `ao_on_hotload()` callback
  * Newly added ability types are also attached to players who already exist when the hotload completes
* The menu beside **Add Client** provides **Hotload code (Alt+F9)**, **Hotload assets (Alt+F10)**, and persistent automatic-hotload toggles
* Changed, newly added, and removed asset IDs can hotload into a Start Game server and its clients while preserving live asset references and Spine bindings
  * Removed IDs disappear from new lookups and CSL handle tables while existing raw references retain their last-good objects; re-adding the same ID revives it in place
  * Spine asset reloads also refresh live-event presenter ghosts
* Hotload compile errors are forwarded to connected clients, and editor checkpoints from an older code generation are rejected instead of restoring incompatible VM memory

</details>

<details>

<summary>Particle Systems and Cosmetic Drawing</summary>

* Added deterministic 2D particle effects through `Particle_System_Component` and `Particle_System_Desc`
  * Supports burst and continuous emission, local and world simulation space, prewarming, rectangular spawn regions, color and size over lifetime, gravity, friction, rotation, and render-layer controls
  * `play()` validates and starts an immutable descriptor, `restart()` replays it, and `stop()` disables it
  * Continuous emitters derive the smallest safe reusable slot pool from emission rate and maximum lifetime
  * WORLD-space drawing cannot advance past its latest birth-position update, including during runtime startup and re-enable gaps
  * Added presets for shotgun blasts, fireworks, explosions, sparks, smoke, dust, fountains, embers, snow, rain, confetti, and magic auras
* Particle evaluation and drawing now run through native quad batching for an approximately 10x speedup
* Added cosmetic-only CSL draw callbacks that run on renderable submissions and skip resimulation
  * Global `ao_draw(dt)` and `ao_editor_draw(dt)` callbacks
  * Component `ao_draw(dt)` and effect `effect_draw(dt)` callbacks
  * Gameplay and interactive UI must remain in `ao_update` or `ao_late_update`

</details>

<details>

<summary>UI and Rendering APIs</summary>

* Added opt-in immediate-mode rich text in CSL and C# through `Text_Settings.rich_text` and `UI.TextSettings.RichText`
  * Supports nested color and absolute or relative size tags plus inline texture images with offset, scale, and rotation controls
  * Rich text preserves shaping across style runs, wraps correctly, and keeps line height based on the configured base text size
* Added `.RADIAL` to CSL `Fill_Direction` and C# `IM.FillDirection`
  * Radial fills start at 12 o'clock; signed `-1..0` values fill counterclockwise and `0..1` values fill clockwise
  * Added C# `IM.PushFillAmount`, `IM.PopFillAmount`, and `IM.PUSH_FILL_AMOUNT`
* Added `Quad_Params.rotation_degrees` for rotated CSL immediate-mode quads
* Added `UI.get_next_serial()` and `UI.set_next_serial()` for preserving deterministic immediate-mode UI identity across custom drawing flows

</details>

<details>

<summary>New CSL APIs and Compiler Behavior</summary>

* CSL inventories now support `for item, slot: inventory.slots()`
  * Every slot is visited in order, and empty slots yield `null`
* Added `Save.delete_game_key(key)` for deleting either a string or integer game-wide save value through the normal batched save flow
* Added hexadecimal integer literals, `Math.exp`, `Math.log`, and `rng_mix`
* Multi-return signatures support the parenthesized `proc() -> (A, B)` form, and declaration arity mismatches now report a targeted error
* CSL type information now exposes tuple element types and enum backing types and distinguishes `ref T` references from `*T` pointers
* `try_get_constant_procedure` now resolves compatible overloads, inherited methods, and the nearest same-named method declaration in the inheritance chain
* Arithmetic and comparisons between different primitive numeric types now choose a common type only when both conversions are lossless
  * This includes exactly representable integer-to-float widening and preserves the flexibility of untyped negative constants; lossy conversions still require an explicit cast
* Polymorphic procedure values can now be inferred from an expected callback type, including nested generic callback signatures
* Contiguous integer switches compile to jump tables for faster dispatch
* Misplaced file-scope loops and invalid method extensions now report targeted compiler errors instead of entering broken parser paths
* Fixed false link-ID collisions involving polymorphic enum and bit-field values and equivalent generic instantiations

</details>

<details>

<summary>C# API Changes</summary>

* Added `Save.DeleteGameKey(id)` for deleting either a string or integer game-wide save value
* Added strongly typed item definitions and instances
  * Set `ItemDescription.DefinitionType` to an `Item_Definition` subclass and `ItemDescription.InstanceType` to an `Item_Instance` subclass before calling `Item_Definition.Create()`
  * Definition fields are initialized independently by client and server code and are not serialized
  * Instance fields marked `[Serialized]` sync from server to clients and are saved and restored with the item; unmarked fields remain runtime-only
  * After directly changing a serialized instance field on the server, call `Inventory.MarkItemDirty(item)`; use `ServerForceSyncInventory` when clients must receive it immediately

</details>

<details>

<summary>Live Events and Player Experience</summary>

* Expanded the live-event API in CSL
  * Added `Live_Events.is_active`, `Live_Events.is_local_player_presenting`, `Live_Events.presenter_count`, and `Live_Events.get_presenter`
  * `Live_Event_Presenter` exposes the presenter's slot, display name, speaking state, and client-local ghost entity
* Expanded the live-event API in C#
  * Added `LiveEvents.IsActive`, `IsLocalPlayerPresenting`, `PresenterCount`, `GetPresenter`, and `TryGetPresenterBySlot`
  * `LiveEventPresenter` exposes the same presenter and ghost state
* Presenter ghosts are excluded from normal scene and component iteration and are cleaned up when an event ends
* Live-event streaming now has more resilient buffering, playout recovery, presenter transforms, skin and Spine animation playback, voice handling, and failure reporting
  * Multi-presenter streams now share an ordered mixer timeline, preserve genuine simultaneous speech, substitute bounded silence for missing chunks, and publish only contiguous completed parts
* Player rig and cosmetic assets were cleaned up, including more reliable coloring and rendering for live-event ghosts
* Mobile players who repeatedly tap an aimed ability instead of dragging now see an animated drag gesture hint

</details>

<details>

<summary>Editor and Developer Workflow</summary>

* Inspector component workflows now support **Copy Component**, **Paste Values**, and **Paste As New**
  * Components can be dragged between entities to move them while preserving their values and references
  * Paste operations work across multi-selected entities when the component types are compatible
* Texture settings can be edited and applied to multiple selected project assets at once
* Open prefab editors now detect external filesystem changes and offer to reload the affected prefab instead of silently overwriting those changes
* New projects now start with a preprocessed default player rig and matching scene configuration
  * Production editor builds copy the baked template immediately, while asset-less development builds generate the same fallback locally
* Cloud-build bundles now rebuild their CSL script section from authoritative project source alongside their scene data
* `assets_validate` now runs preprocessing and returns structured diagnostics, including for preprocessing exceptions and malformed Spine atlas fields
* Scene-persisting automation tools now warn when an active Start Game session must restart before their changes become visible
* Added `memory_snapshot` and `memory_report` automation tools for comparing live allocations and tracking leak candidates in running Start Game clients or servers
* Live client automation now shares one action table with the scripted `Test.*` API
  * `client_input` replaces `client_click`, `client_click_and_hold`, `client_press_key`, and `client_type_text`; it sends `click_at`, `click_button`, `use_ability`, `scroll_widget`, `tap_key`, `press_key`/`release_key`, `type_text`, and world-space `set_mouse`/`click_mouse`
  * `client_action` replaces `test_action` for waits, movement, interaction, admin commands, state reads, assertions, and save/currency/inventory mutation; `describe_client_action` replaces `describe_test_action` and reports which tool owns an action
  * Every click blocks until the client and server observed it and returns a `delivery` report covering gesture delivery, widget activation, UIDoc handler execution, and server acknowledgement
  * `in_game_screenshot` now waits for pending asset loads to settle before capturing, like `Test.screenshot`
  * Added `Test.click_at`, `Test.tap_key`, `Test.press_key`, `Test.release_key`, and `Test.type_text` to the scripted Test API
* Multiphase builds now expose additive phase-specific MCP tools and skills: world authoring first, scripting and live iteration second, then validation in the final review phase
* MCP tool definitions now avoid duplicated client-action and live-testing guidance, and minified JSON responses no longer retain separator spaces
* Bundled Claude Code sessions now suppress the unused LSP and report-findings tool schemas
* macOS editor storage now uses the user's Application Support directory, project discovery tolerates unreadable folders, and bundled Claude, Codex, and OpenCode runtimes were refreshed on macOS and Windows

</details>

<details>

<summary>Runtime Performance and Reliability</summary>

* C# component dispatch and offscreen leaderboard rendering do less per-frame work
* Rich-text shaping, particle drawing, contiguous switches, and polymorphic compilation are faster and more reliable
* Suspending or resuming the app releases keyboard, mouse, and touch state so mobile multitasking cannot leave controls stuck
* Custom C# item payloads survive netsync memory relocation, and force-syncing an inventory also marks its serialized item changes for persistence
* Replacing JSON-backed CSL values no longer invalidates aliased strings or managed arrays
* Large CSL programs keep immutable bytecode out of the fixed non-networked game-state region, reducing Start Game and hotload memory pressure
* Start Game uses a larger non-networked arena and bounds internal hashtable probes so corrupt tables fail loudly instead of hanging

</details>
{% endupdate %}

{% update date="2026-08-03" %}

## Protocol 46 - August 3rd, 2026

Protocol 46 adds runtime tilemap authoring, engine-managed live events, device emulation, substantially richer UIDoc styling, and new CSL and C# APIs. It also improves keybinds, inventory security, cloud builds, automation, asset loading, voice, and developer-facing diagnostics.

<details>

<summary>Compatibility and Migration</summary>

* Player Spine tracks
  * The engine-owned player skin animation moved from track 10000 to track 10
  * Tracks 0, 1, 2, and 10 are reserved; custom player animation layers should use tracks 3 through 9
* C# inventory handles
  * `Item_Definition.Id` and `Item_Instance.Definition` are now read-only and cached
  * Remove code that assigns either property
* C# player-list rendering
  * `Player.GetSpineInstanceForPlayerList()` was removed
  * The built-in player list now renders profile avatars
* UIDoc binding expressions
  * Treat `class` and `data-key` values as static; `{{...}}` interpolation is supported only in text and image `src`
  * `data-for-key`, `data-scroll-zoom`, and `data-style-*` take direct binding expressions without mustaches
  * Use `data-style-color`, `data-style-opacity`, image effects, or explicit list contents for dynamic presentation
  * `data-if` is limited to top-level bool bindings, with optional `!` inversion

</details>

<details>

<summary>Runtime Tilemap API</summary>

* Added full runtime tilemap access in both CSL and C#
  * Query and resize tilemap dimensions
  * Add, remove, configure, and clear ground or wall layers
  * Configure automatic or manual layer sorting, tile size, tint, masks, outlines, wall tops, collision, inset, and offset
  * Add, replace, weight, scale, offset, and remove a layer's textures
  * Query, set, and clear individual tiles
  * Convert between tile, local, and world coordinates
* CSL additions include `Tile_Layer_Kind`, `Tile_Layer_Mode`, and the new `Tilemap_Component` methods
  * CSL tilemap mutations are predicted scene state and participate in rollback and reconciliation
* C# additions include `TilemapLayerKind`, `TilemapLayerMode`, and matching `Tilemap_Component` properties and methods
  * C# tilemap mutations affect the current simulation only; multiplayer games must invoke equivalent changes on every peer through their existing RPC flow
* Layer indices shift when a layer is removed, invalid indices fail loudly, wall height must be at least 2, and each layer supports at most 256 textures
* Tilemap layer tinting now affects rendered tiles
* Tilemap textures now have independent X/Y repeat scale and tile-space offset controls, including wall-top textures
* Tilemaps now follow entity X/Y scale in rendering, editor painting, coordinate conversion, collision, and navmesh input
* Transform-only tilemap collision updates reuse cached local geometry instead of rescanning and regrouping tiles
* Vertically expanded wall rows preserve their independent outlines and Y sorting when they overlap, including across chunk boundaries

</details>

<details>

<summary>UIDoc UI and Styling</summary>

* Added project fonts through CSS `@font-face`
  * TTF and OTF `Font` assets can provide multiple weights and styles for one family
  * UIDoc selects the nearest face and can synthesize a missing bold or slanted face
  * Fonts load asynchronously and automatically invalidate text layout when ready
* Expanded text styling with `font-family`, real `font-weight`, `font-style`, `letter-spacing`, improved line-height behavior, and up to eight text shadows
* Added `data-text-reserve` for stable intrinsic layout when frequently changing text has a known widest sample
* Expanded backgrounds and effects
  * Linear, radial, and conic gradients with up to eight stops and Oklab or sRGB interpolation
  * Up to eight box shadows, including inset shadows
  * `filter: blur(...)`, alpha-aware `drop-shadow(...)`, and `backdrop-filter: blur(...)`
  * `image-tint`, `image-grayscale`, directional and radial image fills, bound fill amounts, and improved `object-fit`
  * Added paint-only `data-style-color` and `data-style-image-fill-amount` bindings that avoid structural layout invalidation
* Expanded layout support
  * `calc(...)` addition and subtraction for supported lengths
  * `position: fixed`, richer inset/size units, relative translation percentages, flex alignment and wrapping improvements, and stricter property-specific value validation
* Tailwind-style lowering now covers more layout, text, color, shadow, transform, and image-effect utilities
  * Responsive and interaction variants, bracket values, and `@apply` are supported when they lower to the UIDoc subset
* Added more reliable keyed-list identities and documented exact runtime test selectors for repeated controls
* Scroll layout, zooming, nested state restoration, font layout, clipping, and transformed hit testing are more reliable
* UIDoc draws faster, and paint-only binding changes avoid unnecessary relayout
* Unsupported declarations, values, selectors, malformed HTML, and unsupported media queries now produce clearer asset diagnostics

</details>

<details>

<summary>New CSL APIs and Behavior</summary>

* Haptics
  * Added `Haptics.play_impact` with `.LIGHT`, `.MEDIUM`, and `.HEAVY` impact types
* Ads
  * Added `Ads.request_interstitial() -> bool`
  * Rewarded and interstitial ads can now be hosted by the web client as well as native clients
* `World_Progress_Bar.draw` now safely does nothing on the server instead of entering client UI code
* Ability buttons respect `draw_but_dont_use_keybind`, honor remapped bindings, and no longer render the word `Unbound`
* CSL chat-command arguments typed as `Player` now receive the player named in the argument instead of the command sender

</details>

<details>

<summary>C# API Changes</summary>

* Added `Camera.IsVisible` overloads for a world point, world rect, `Sprite_Renderer`, and `Spine_Animator`
  * Clients test the local camera; servers return true when any player camera sees the target
  * The optional `apron` expands the tested bounds
* Added `UI.TextSettings.LetterSpacing`
* Inventory and items
  * Added `Inventory.GetItemQuantityById`, `Inventory.HasItemById`, and `Inventory.GetFirstItemById`
  * Added allocation-conscious `Item_Instance.GetMetadatas(string[] keys, ref string[] values)`
  * Added `Inventory.RequireOwnership`, `OwnerUserIds`, `AddOwnerUserId`, `RemoveOwnerUserId`, and `ClearOwnerUserIds`
  * Built-in player inventories automatically require their player's user ID
  * Custom inventories remain shared by default; adding an owner automatically enables ownership enforcement
  * Unauthorized client merge, swap, and use commands are rejected by the server
* Save callbacks
  * `Save.GetOfflinePlayer` now invokes its callback exactly once for every completed request
  * Unknown players and failed requests supply empty data, and failures are logged
  * Ordered save-data reads follow the same callback-on-failure contract with an empty result

</details>

<details>

<summary>CSL Compiler, JSON, and Project Validation</summary>

* Constant fixed-size arrays now report the correct `.count`
* CSL compilation is faster and uses less temporary memory, and inclusive and reverse loops execute with lower VM overhead
* The compiler now reports `No CSL script files found` for an empty scripts tree instead of accepting an unusable project
* JSON handling is safer and more standards-compliant
  * Strings and object keys are escaped correctly when serializing
  * Escaped object keys are decoded when parsing
  * Mixed-type arrays no longer enter the numeric-array serializer and crash
  * Reading a JSON array into a fixed-size array stops at the shorter length instead of reading or writing out of bounds
* Added compiler semantic-analysis output for editor and language-server integrations on Windows and macOS
  * The output includes compiler diagnostics, declarations, types, scopes, and identifier occurrences

</details>

<details>

<summary>Live Events, Voice, and Player UI</summary>

* Added engine-managed live events with streamed presenter voice, transforms, skins, and Spine animation state
* Audience clients receive synchronized, client-local presenter ghosts without adding those ghosts to replicated gameplay state
* Live-event playback includes buffering, recovery, presenter status, and failure reporting for unstable connections
* Voice capture and playback quality and voice isolation were improved
* The in-game player list now uses current profile avatars and an unknown-avatar fallback
* Chat filtering recognizes word boundaries for short blocked terms, reducing false positives while expanding coverage

</details>

<details>

<summary>Editor and Developer Workflow</summary>

* Added phone and tablet emulation to the editor play toolbar
  * Profiles cover small and large phones, a foldable, and tablets
  * Emulation uses native landscape resolution, safe areas, cutouts, rounded-screen clipping, phone/tablet device classification, and remapped mouse input
  * `Fit` fills the client window; `Physical` estimates real-world display size from monitor density
* UIDoc authoring improvements
  * The visual editor now uses the production runtime more consistently for selection, layout, style editing, generated wrappers, saving, and diagnostics
  * Added `uidoc_create_asset` and live `uidoc_runtime_inspect` automation tools
  * Renamed the generated interface inspection tool from `uidoc_contract` to `uidoc_interface`
* Local asset search now has relevance ranking, aliases, type intent, project/engine/all scopes, pagination, file-change-aware hashes, and world-size metadata
* Project agent setup now writes `opencode.json` in addition to Claude, Cursor, Codex, and generic MCP discovery files
* Cloud builds now package scene source and perform authoritative scene packing from that source
  * Scene-export failures and timeouts surface the relevant server log instead of hanging or silently producing stale output
  * Cloud-build draft projects can still be packaged when the local scripts currently do not compile, so server-side diagnostics remain available
* Editor filesystem failures now produce clearer errors on Windows and macOS
* Editor numeric fields preserve float precision, Windows clipboard paste handles UTF-8 safely, and linked prefab descendants are hidden from the editable hierarchy
* New-project creation rejects the entire games directory and folders that already contain another All Out project
* Exceptionally long entity filenames no longer crash project loading

</details>

<details>

<summary>Automation, Testing, and Diagnostics</summary>

* Game startup now launches a consistent compiled snapshot
  * Source changes during startup, compile failures, launch failures, automation bind failures, process exits, and readiness timeouts return distinct structured errors
* `test_action` accepts common argument aliases, normalizes component paths, and returns clearer invalid-argument, timeout, unavailable-client, ambiguous-target, and not-found errors
  * Live count bounds and inventory moves now use the equivalent CSL `Test.*` parameter names, and `describe_test_action` returns each action's schema, aliases, and example
* Non-idempotent test actions such as interactions and inventory operations no longer fail intermittently when transient input is dropped
* Test clients and dummy peers are cleaned up when a run ends, including partial or failed launches
* Client and server crashes now retain structured process attribution, exit status, CSL and native top frames, artifact paths, and log paths
* Fatal runtime errors shown in the editor and to players include more useful error categories and context
* Automation screenshots, UI inspection, input, test result discovery, and macOS child-process handling are more reliable

</details>

<details>

<summary>Runtime, Platform, and Performance</summary>

* Keybind remapping is now kept per player, validated, saved atomically, restored by action name, and fully reconciled with the server
  * Duplicate assignments are removed consistently and corrupt keybind files are ignored safely
  * Engine-owned UI and fullscreen controls now honor the local player's remapped bindings
* Desktop clients can use the static on-screen joystick with a mouse
* Asset loading and game transitions
  * Bundled preview textures no longer stall unrelated asset loading during startup
  * Android joins do less upfront audio work and avoid asset-loading stalls
  * Failed web downloads and decodes, draw contexts, and game-leave resources release more memory reliably
* Web clients have more accurate memory and frame-time reporting, including clean handling of standby and resume gaps
* Web hosts can set an engine-owned UI scale multiplier without changing game-authored UI scale
* Idle scenes skip unnecessary lighting and tonemapping passes
* Android window, input queue, WebView, fatal-signal reporting, and game-transition lifecycle handling are more robust
* Linux asset processing accepts projects up to 2 GiB and server-side Redis reconnect handling is more resilient
* UIDoc rendering, CSL analysis, runtime tilemap updates, and network prediction recovery are faster and more stable

</details>
{% endupdate %}

{% update date="2026-07-15" %}

## Protocol 45 - July 15th, 2026

Protocol 45 adds UIDoc and scene-owned paint canvases, expands CSL gameplay and rendering APIs, improves live development tooling, and delivers substantial multiplayer, pathfinding, collision, scripting, and runtime improvements.

<details>

<summary>Compatibility and Migration</summary>

* Client version
  * The client version is now 1.45.1
  * Android version code is now 492
* Protocol and game data
  * Protocol 45 clients and servers cannot communicate with protocol 44 builds
  * Deploy matching client and server builds together
  * The game-state memory version increased from 58 to 75
  * Rebuild and republish games and packed scene data after upgrading
* Replicated C# components
  * Replicated component IDs now support values above 255
  * The limit remains 255 serialized components per entity
  * Entity payloads over 65,535 bytes now fail explicitly instead of being truncated
* CSL template strings
  * Backtick strings now support `{expression}` interpolation
  * Literal braces in existing raw backtick strings must be written as `{{` and `}}`
  * A lone closing brace is now a compile error
  * Interpolated templates require `import "core:basic"` and are not compile-time constants
  * Backtick strings without interpolation remain raw constants
* Numeric literals
  * Literals larger than 64 bits now fail compilation
  * Values outside an explicit integer suffix or enum range now fail instead of silently wrapping or truncating
  * Fractional literals can no longer use an integer suffix
* Source builds
  * Native Windows, Linux, and iOS builds now require Rust/Cargo for UIDoc layout support
  * iOS builds also require the `aarch64-apple-ios` Rust target

</details>

<details>

<summary>UIDoc Screen-Space UI</summary>

* Added `.uidoc` directory assets for authoring responsive screen-space UI
  * Each asset contains an `index.html` and can include an `index.css`
  * Supported content includes text, images, buttons, text inputs, conditions, and repeated lists
  * CSL can bind text, bools, floats, image paths, lists, inputs, and events
* Layout and styling
  * Supports responsive flex and block layouts, safe areas, interaction states, and client-specific viewport sizing
  * Supports vertical and horizontal scrolling, nested scroll-state restoration, and bound `data-scroll-zoom`
  * Tailwind-style utilities, responsive and pseudo-state variants, arbitrary values, and `@apply` can be lowered during asset baking when enabled by the stylesheet
  * Layout accounts for each client's viewport, locale, safe area, and replicated UI scale
* New CSL surface
  * Added `UIDoc_Asset`, `UIDoc_Event`, `UI.uidoc`, binding and list helpers, event polling, and text-input value access
* UIDoc uses a deliberately constrained HTML/CSS subset
  * It is deterministic engine UI, not an embedded browser
  * JavaScript, browser APIs, forms, external URLs, CSS grid, variables, transitions, and keyframes are not supported
  * Unsupported output fails asset validation instead of silently degrading
* Existing immediate-mode UI and UIK projects remain supported
  * Guidance for new screen-space UI now favors UIDoc

</details>

<details>

<summary>Visual UIDoc Editor</summary>

* Selecting a UIDoc replaces the entity-centric scene, hierarchy, and inspector with UIDoc authoring tools
* The scene view uses the production UIDoc parser, layout, and renderer for an exact runtime-backed preview
* Elements can be selected, moved, resized, inserted, duplicated, deleted, reordered, and reparented
* Design and Styles inspectors edit common HTML and CSS properties, including colors
* The Interface inspector infers fields, inputs, lists, and actions directly from UIDoc markup
* Saving generates a typed CSL wrapper under `scripts/generated/uidoc`
* UIDoc edits have document-aware save, undo/redo, external-change detection, and compiler diagnostics

</details>

<details>

<summary>New CSL Gameplay and Rendering APIs</summary>

* Scene-owned dynamic canvases
  * `Dynamic_Canvas` can create, destroy, fill, stamp, set, and sample pixel canvases
  * `Sprite_Renderer` can display a canvas
  * Spine attachments can override their texture with a canvas and optionally use skeleton-space UVs
  * Animated Spine hit positions can be converted back to stable canvas coordinates
  * Canvas state participates in sync, prediction, rollback, and reconciliation
  * Current limits are 512×512 pixels, 16 canvases per scene, and 4 MiB of canvas pixels per scene
* Scene color sampling
  * `Player.request_scene_color_sample` and `Player.try_get_scene_color_sample` support eyedropper-style mechanics
  * Sample results are client-authored visual input and must not be trusted as authoritative game state
* Dynamic canvas methods are currently available from CSL
  * C# receives the generated `Dynamic_Canvas` handle but not the full canvas API
* Interactables
  * Added subtitle getters, setters, and editable subtitle color
* Emotes and effects
  * Added equipped-emote checks, counted block reasons, trigger and cancellation APIs
  * Added `Effect_Base.get_duration_remaining`
* Inventory
  * Added `Inventory.has_item_id`
  * Added `Inventory_Draw_Options.on_before_draw` and `on_after_draw`
* Rendering and interpolation
  * Added `get_fixed_delta_time`, `Camera.size_last_frame`, `world_to_screen_interpolation_offset`, and `UI.quad_interpolated`
  * Added `UI.player_avatar` for drawing a static player avatar
  * Added interpolated aiming helpers and an Entity overload for tutorial arrows
* Spine and player materials
  * Added helpers for using a player's material and destroying an entity after its current animation
  * Added canvas painting options and skeleton-space attachment overrides
  * Added `color_replace_get_color` for reading avatar palette colors
* Sound documentation now covers `SFX.fade_out_and_stop` and controlling returned sound IDs from server-side CSL

</details>

<details>

<summary>Player and Runtime Changes</summary>

* CSL games now support the standard emote wheel
  * Equipped thumbnails, synchronized effects and sounds, looping, gameplay block reasons, and movement cancellation are supported
  * Fixed several emote state and headless-server crashes
* Interaction prompts can display a localized, independently colored subtitle
* Instant interactables with no hold duration now trigger correctly from a mobile tap
* Aiming indicators, target reticles, tutorial arrows, and dropped-item UI now interpolate more smoothly
* Multiplayer
  * Ongoing state and drop-in traffic is substantially smaller
  * Recovery from missing updates and long hitches is more reliable
  * Prediction now continues catching up instead of accumulating a permanent resimulation backlog
  * Web clients use the correct simulation budget on high-refresh-rate displays
  * Rollback no longer repeats UI side effects such as click sounds
* Scroll views
  * New views remain at the start until deliberately scrolled
  * Horizontal-only views accept horizontal wheel input
  * Transient zero-sized layouts no longer corrupt scroll offsets
  * Recreated UIDoc elements retain their scroll position
* UI scale now participates correctly in prediction and replay, reducing layout and hit-target mismatches after changing scale
* Android hardware volume buttons continue controlling system volume while in-game
* Global leaderboard names containing formatting characters such as `%` now display literally
  * Offscreen leaderboards are also culled
* Dropped items can be culled visually without freezing their gameplay movement
* Reparenting an entity beneath a disabled entity immediately applies the correct disabled state
* Rewarded-ad and CSL purchase grants more reliably wait for client replication before processing
* Restored the built-in CSL green-button asset reference
* All Collider-derived components on an entity now participate in CSL physics
  * Projects using multiple colliders may observe newly correct contacts

</details>

<details>

<summary>CSL Compiler and Project Workflow</summary>

* Compiler diagnostics
  * Capturing procedure literals remain unsupported and now produce an explicit error
  * `return` outside a procedure now reports an error instead of crashing
  * Very long boolean chains and large switches no longer overflow the compiler's native stack
* Script-heavy workloads benefit from optimizer, bytecode-inlining, and value-formatting improvements
* Core library vendoring
  * Opening a CSL project copies the engine core library into `scripts/.ao_core`
  * `import "core:*"` resolves against that project copy
  * The copy is included when publishing and is not rewritten when unchanged
  * Treat `.ao_core` as generated content and do not edit it manually

</details>

<details>

<summary>C# API Changes</summary>

* `Vector2`, `Vector3`, and `Vector4` now explicitly implement component-wise `Equals` and `GetHashCode`
  * Their behavior in dictionaries and sets is now consistent
* Added `Camera.WorldToScreenInterpolationOffset`
* Built-in aiming indicators and target reticles now use frame interpolation
* Aiming helpers gained optional interpolation-offset parameters
  * Normal calls remain source-compatible
  * Reflection, delegates, or method groups relying on the previous exact arity may need updating

</details>

<details>

<summary>Editor, Automation, and Testing</summary>

* Editor `compile` can hot-reload CSL into a running editor-launched game and reconnect clients to the updated state
  * Scene edits still require a stop and restart
* Restored and hardened live game tools for starting and stopping games, screenshots, UI-tree inspection, clicking and holding, keyboard input, and text input
* Added `test_action` for running individual Test.Runner actions in a live game
  * Supported actions include waiting, movement, navmesh pathfinding, interaction, abilities, assertions, inventory and save operations, and variable or component inspection
* Added `assets_validate`, `uidoc_interface`, and `uidoc_diagnostics`
* Direct `client_wait` and `client_health` integrations should migrate to `test_action(wait)` and the newer automation health classification
* `Test.pathfind_to` now follows the navmesh
* Added `Test.assert_balance_range` for timing-tolerant economy assertions
* Injected test movement is no longer discarded by mobile joystick recomputation
* Screenshot requests time out cleanly instead of occasionally hanging
* Test execution fails fast when a game launch is already in progress
* Automation and compile failures now provide clearer diagnostics and stack traces

</details>

<details>

<summary>Performance, Hosting, and Stability</summary>

* Navmesh pathfinding and rebuilds are substantially faster, especially for repeated paths and unreachable targets
* Collision-heavy CSL games now avoid testing every collider against every other collider
* Web builds use a smaller initial memory reservation and clean up failed asset decode and download paths more reliably
* Linux-hosted servers account for container memory limits while loading assets, reducing startup and prewarming out-of-memory failures
* Asset prewarming and UIDoc replication have lower peak memory use

</details>
{% endupdate %}

{% update date="2026-06-13" %}

## Protocol 44 - June 13th, 2026

This protocol update focuses on CSL compiler performance and memory use, better callback resolution, smoother sync/interpolation behavior, and several runtime fixes for strings, assets, and world-space UI.

<details>

<summary>Sync and Interpolation</summary>

* Network sync now uses the protocol 44 32hz variable sim/sync cadence
  * Game simulation now advances at a lower fixed cadence than rendering
  * Rendering can still look smooth by drawing with an interpolation offset from the previous rendered position to the current simulated position
* Entity-attached rendering
  * World-space rendering calls inside supported component callbacks are automatically attached to that component's entity and interpolated
  * In those callbacks, `UI.push_world_draw_context()` is enough for labels, prompts, health bars, and similar entity-following visuals to move smoothly between sim ticks
  * Outside component callbacks, use `UI.begin_world_space_ui(entity)` and `defer UI.end_world_space_ui()` when drawing world-space UI or other immediate-mode visuals that should follow an entity
  * `UI.begin_world_space_ui(entity)` pushes the world draw context and uses the entity's built-in interpolation data
  * Use `entity.mark_teleported()` when an entity moves discontinuously and you explicitly do not want the next render to interpolate across that jump
  * Large teleports are also detected automatically: if an entity moves more than 3 world units since the previous frame, interpolation is skipped for that frame
* Manual interpolation offsets
  * Use `UI.push_interpolation_offset(offset)` before any custom rendering that needs interpolation
  * Always pair it with `UI.pop_interpolation_offset()`, usually through `defer UI.pop_interpolation_offset()`
  * The offset should represent the movement from the last rendered position to the current position
  * Component entity anchoring uses the same interpolation-offset stack, so nested manual offsets follow normal push/pop order
* Custom non-entity positions
  * Use `Position_Interpolation_Helper` in your own class or struct when you own a position that is not covered by an entity's built-in interpolation
  * Store one helper per moving thing, call `.update(current_position)`, and pass the returned offset to `UI.push_interpolation_offset`
* Animated fill amounts
  * Use `Float_Interpolation_Helper` with `UI.quad(..., params={fill=UI.quad_fill(helper.update(progress), .RIGHT)})` for smoothly animated fills such as progress bars
  * Use `UI.quad_fill(progress, .RIGHT)` when the fill amount does not need interpolation
  * `.RIGHT` fills left to right as the amount moves from `0` to `1`; `.NONE` leaves the quad unfilled and is the zero-initialized value
  * `Quad_Params` also accepts `nine_slice` data for the same draw call

```csl
Particle :: class {
    position: v2;
    velocity: v2;
    interp: Position_Interpolation_Helper;

    update :: method(dt: float) {
        position += velocity * dt;

        UI.push_interpolation_offset(interp.update(position));
        defer UI.pop_interpolation_offset();

        // Draw the particle here.
    }
}
```

* Interpolation anchor context
  * Supported component lifecycle callbacks now automatically push that component entity's interpolation offset while the callback runs
  * This applies to `ao_start`, `ao_update`, `ao_late_update`, `ao_end`, `ao_on_interactable_used`, and `ao_on_holding_interactable`
  * `ao_can_use_ability`, `ao_can_use_interactable`, and `ao_on_state_sync` are intentionally not anchored; keep them small, fast, and pure
  * This applies to sim-owned world-space draw contexts only; present/combine rendering does not read component interpolation anchor state
  * C# component update loops also scope this with push/pop per component, so exceptions cannot leak a stale interpolation anchor

</details>

<details>

<summary>CSL Language and Compiler Changes</summary>

* New procedure-resolution directives
  * `#optional_procedure_of_call(call)` was added
  * It works like `#procedure_of_call(call)`, but unresolved optional calls return an empty procedure value instead of producing a hard error
  * `#procedure_types_are_leniently_compatible(src_type, dst_type)` was added as a compile-time bool check for callback/interface compatibility
* Interface and callback matching
  * Interface procedure requirements now allow compatible derived-class parameter types where the call is safe
  * Overloaded interface method implementations now resolve to the concrete implementation on the actual receiver type
  * Procedure type-vs-overload mistakes now produce clearer compile errors
* Polymorphic assignability constraints
  * Polymorphic type parameters can now constrain assignability with syntax like `$T/Base`
  * This supports APIs that accept a base type while preserving the caller's concrete type
* Range loop bounds
  * Integer widening is now allowed for range bounds when the widening conversion is safe
  * Invalid non-widening range bounds now report a compile error instead of crashing
* New GC helper
  * `#unrootify_object(value)` was added
  * It removes a root from an existing object without freeing the object immediately
* Diagnostics and performance
  * Misplaced `give` statements now produce a targeted error
  * Source locations were compacted internally, preserving file/line reporting while reducing compiler memory
  * The compiler received major memory and throughput optimizations for large scripts

</details>

<details>

<summary>Core API and Runtime Changes</summary>

* `Interactable.set_listener`
  * Now accepts a concrete component listener type instead of collapsing the listener to `Component`
  * Callback lookup now uses CSL call resolution through `#optional_procedure_of_call`
  * Inherited and overload-nested `can_use`, `on_interact`, and `on_holding` callbacks now resolve to the right concrete listener procedure
  * `Interactable` now also declares the `can_use` interface callback
* World-space UI
  * `UI.begin_world_space_ui(entity)` now pushes world draw context in addition to interpolation offset
  * Passing `null` is supported and uses a zero interpolation offset
  * `UI.end_world_space_ui()` now pops both interpolation and draw context
* Global leaderboard package
  * `core:global_leaderboard` adds a reusable `Global_Leaderboard : Component` for world-space ranked scoreboards backed by ordered saves
  * Import it with `import "core:global_leaderboard"` and add `Global_Leaderboard` to a scene entity
  * Set `leaderboard_id` on the component, optionally set `optional_title`
  * On the server, call `Global_Leaderboard.increment_score(player, leaderboard_id, amount)` to add to a player's score
* String getters
  * `Player.get_username()`, `Player.get_user_id()`, `Player.get_name_override()`, and `Entity.get_name()` now cache rooted CSL strings
  * Repeated calls avoid unnecessary string allocation while still updating when the native value changes
* Asset handles
  * Spine skeleton, attachment texture, and cosmetic APIs now resolve CSL asset handles through the scene asset lookup table
  * This fixes cases where CSL-visible assets are represented by script stubs instead of direct native VM objects
* Formatting
  * `tprint`/formatted string output now recognizes `Format_Int` and `Format_Float` by link id
  * Padded integer and float formatting now works in cases where the format helper type is not pointer-identical to the cached runtime type

</details>
{% endupdate %}

{% update date="2026-05-21" %}

## Protocol 43 - May 27th, 2026

This protocol update tightens CSL validation, removes several legacy APIs, changes UIK interaction handling, and updates a few core library behaviors.

<details>

<summary>Breaking CSL Changes</summary>

* Struct and class parameters
  * Explicit `$` on struct or class parameters is now illegal
  * `struct($T: typeid)` → `struct(T: typeid)`
  * This affects patterns like `List`, `Hashtable`, and `Component_Iterator`
  * Polymorphic procedures like `proc($T: typeid, ...)` still work
* Stray `$identifier` usage
  * Standalone `$identifier` is now rejected instead of being treated like `identifier`
* Reserved keywords
  * `bit_field` is now a reserved keyword
  * Any identifier named `bit_field` will now fail
* String and char escapes
  * Unknown escape sequences now produce a compile error
  * They no longer slip through or panic at runtime
* Invalid code now fails earlier
  * Calling non-procedure or non-polymorphic types now errors
  * Comparing incompatible types now errors

</details>

<details>

<summary>Core API Breaks</summary>

* `core:ao/generated`
  * `src/csl/core/ao/generated.csl` was removed
  * Its contents were folded into `core:ao`
  * Direct imports of `core:ao/generated` now break
* `game_support.csl`
  * `src/csl/game_support.csl` was deleted
  * Code relying on its empty `Player :: class : Player_Base` must now define `Player` directly
* Generated `self` fields
  * Generated `self` fields were removed from wrappers like `Entity`, `Component`, `State_Machine*`, `Item_Definition_Base`, `Item_Instance_Base`, and `Inventory_Base`
* Item definition getters
  * `Item_Definition_Base.get_name()` and `Item_Definition_Base.get_id()` were removed from the base API
  * `Item_Definition` still keeps soft-deprecated getters
  * Code typed as `Item_Definition_Base` must use `.name` and `.id`
* Spine instance hierarchy
  * `Spine_Instance_Base` was removed
  * `Spine_Instance` now inherits `Spine_Instance_Fields` directly
  * Explicit references or casts to `Spine_Instance_Base` now break
* Skeleton APIs
  * `Spine_Animator.set_skeleton()` and `Spine_Instance.set_skeleton()` now return `u64`
  * `get_skeleton()` now takes an optional `id: u64 = 0`
* Collider hierarchy
  * `Circle_Collider`, `Box_Collider`, `Polygon_Collider`, and `Edge_Collider` now inherit from `Collider`
  * They no longer inherit directly from `Component`
  * Normal component usage should still work
  * Reflection and direct parent checks can break

</details>

<details>

<summary>UIK Breaks</summary>

* Interact handles were removed
  * `UIK.Interact_Handle` was removed
  * Interactive APIs now return `Interact_Result` directly
  * This affects `panel_begin_interactive`, `toggle`, `card_end`, both `tab` overloads, `button`, `icon_button`, `icon_button_label`, and `title_area`
* Resolve flow changed
  * `UIK.resolve(handle)` was removed
  * `UIK.clicked`, `UIK.hovering`, `UIK.pressed`, and related helpers now take `Interact_Result`
  * You can also read `.clicked`, `.hovering`, and related fields directly
* Deferred handle patterns
  * Old patterns that store handles and resolve them after `UIK.end()` should be rewritten to the new simpler pattern
* Yellow enum names
  * `..._YELLOW1` was renamed to `..._YELLOW`
  * `..._YELLOW2` was renamed to `..._ORANGE`

</details>

<details>

<summary>Library and behavior changes</summary>

* Math helpers
  * Generic `lerp`, `clamp`, `min`, and `max` were replaced with concrete overloads
  * `lerp` now supports `v2`, `v3`, `v4`, and `float`
  * `clamp`, `min`, and `max` now support `int` and `float`
  * Calls on other types can now break
* UIK layout helpers
  * `rect_sidebar_left`, `rect_sidebar_right`, `rect_topbar`, `rect_hotbar`, and `rect_dialog` changed layout behavior
  * Their signatures stay the same
  * Existing layouts may shift

</details>

<details>

<summary>Developer workflow</summary>

* `csl.exe <folder>` now defaults to compile and run
* Use `csl.exe <folder> -no_run` for compile-only behavior

</details>
{% endupdate %}

{% update date="2026-04-07" %}

## Protocol 42 - April 16th, 2026

This protocol update brings major CSL breaking changes, stricter runtime enforcement, an overhauled SFX system, and several new engine APIs.

<details>

<summary>Breaking Changes</summary>

* Type system
  * `b8`, `b16`, `b32`, and `b64` were removed. Only `bool` remains.
  * Scripts using those type names will fail to compile.
* Entity hierarchy fields were replaced with methods
  * `entity.parent` → `entity.get_parent()`
  * `entity.first_child` / `entity.last_child` → `entity.get_first_child()` / `entity.get_last_child()`
  * `entity.next_sibling` / `entity.prev_sibling` → `entity.get_next_sibling()` / `entity.get_prev_sibling()`
  * `entity.first_component` / `entity.last_component` → `entity.get_first_component()` / `entity.get_last_component()`
* Component navigation fields were replaced with methods
  * `component.prev_component_on_entity` → `component.get_prev_component_on_entity()`
  * `component.next_component_on_entity` → `component.get_next_component_on_entity()`
* Component state fields were replaced with accessors
  * `component.enabled` → `component.get_enabled()` / `component.set_enabled()`
* Component iterator updates
  * `next(ref Component_Iterator)` was removed. Use `.next()` instead.
* Effects system was restructured
  * `entity.active_effect` → `entity.get_active_effect()` and now safely returns `null` when no effects exist
  * `entity.first_effect` → `entity.get_first_effect()`
  * `entity.last_effect` → `entity.get_last_effect()`
* List construction changed
  * `List.append` is now hard-deprecated for list construction. Use `[..]T` instead.
* Math functions
  * `atan2` changed parameter order from `atan2(x, y)` to `atan2(y, x)` to match standard C behavior
  * Generic `min(a, b)` and `max(a, b)` procedures were removed from `basic.csl`
  * `normalize(v)` no longer includes a zero-length safety check and may now produce `NaN` or `inf`
  * `sin`, `cos`, `atan2`, `pow`, and `sqrt` changed from foreign calls to intrinsic VM opcodes
  * Serialized bytecode is incompatible with previous builds
  * New `f64` overloads were added for `sin`, `cos`, `atan2`, `pow`, and `sqrt`
* Removed APIs
  * The `Gif` asset class was removed entirely, including the `Gif` type, `UI.Gif()` widget, `UIGif` component, and related internal calls in C# and CSL
  * `Sprite_Renderer.WaitForLoad` was removed and now only exists as an obsolete no-op in C#
* Runtime enforcement
  * UI functions now panic outside player update context on the client
  * This affects `ui_button`, `ui_begin_button`, `ui_end_button`, `ui_push_scroll_view`, `ui_pop_scroll_view`, `ui_compute_scroll_bar_rect`, `ui_drag_drop_source`, `ui_drag_drop_target`, `ui_blocker`, `ui_begin_modal`, and `ui_end_modal`
  * These must be called from `core_player_update` or `core_player_late_update`
* SFX system overhaul
  * SFX playback is now authoritative on the server
  * The server tracks active sounds persistently, including ID, duration, elapsed time, and fade-out state
  * Clients now mirror the server's active sound list
  * `sfx_stop` now works correctly across the network

</details>

<details>

<summary>CSL Language Changes</summary>

* Method call syntax now uses `.` instead of `->`
  * `b->set_x(20);` → `b.set_x(20);`
* Fixed-size array literals now support values directly
  * `[4]int{1, 2, 3, 4}` is now valid
* Casting now supports prefix syntax in addition to suffix casting
* Half-closed ranges now support `^`
* Hashtables are now supported
* Class members now support default values, including reassignment in derived classes
* Implicit integer widening is now allowed for safe widening conversions
  * Example: `s32` → `s64`
* `switch` cases now support multiple values and inclusive ranges

```csl
switch level {
    case 1, 2, 3: tier = .BEGINNER;
    case 4..10:   tier = .INTERMEDIATE;
    case 11..20, 25, 30..50: tier = .ADVANCED;
    default:      tier = .UNKNOWN;
}
```

{% hint style="warning" %}
Migration tooling note: do **not** blindly replace every `->` with `.`. Return type definitions still use `->`, so a global search-and-replace will corrupt valid code.
{% endhint %}

</details>

<details>

<summary>Deprecations</summary>

* `case:` with no expression in a `switch` is deprecated. Use `default:` instead.
* Duplicate `default` cases now produce a compile error.
* `get_real_time()` is now soft-deprecated. Use `rng_root_seed()` for RNG seeding.
* `rng_seed_time()` is now soft-deprecated and returns `rng_root_seed()` internally.

</details>

<details>

<summary>New APIs</summary>

* `Datetime`
  * Includes `year`, `month`, `day`, `hour`, `minute`, and `second` as `s64`
* `get_nanoseconds_since_epoch() -> s64`
  * Returns UTC nanoseconds
* `get_utc_datetime() -> Datetime`
* `rng_root_seed() -> u64`
  * Returns the deterministic game-instance RNG seed
* `SFX.fade_out_and_stop(id, fade_time)`
* `Player_Base.get_name_override() -> string`
* `Player_Base.set_name_override(name)`
* `core_globals.server_on_chat_message_received`
  * Callback signature: `proc(player: Player, message: string)`
* `Texture_Asset.get_uvs() -> (v2, v2)`
  * Returns low and high UV coordinates
* `Time.nanoseconds_since_epoch() -> u64`
* `SFX_Desc.local_only: bool`
  * Hard-deprecated. Use `SFX_Desc.specific_to_player`.
* `SFX_Desc.specific_to_player: Player`
  * Tracks the sound on the server but only triggers playback on the target player's client
* `Sprite_Renderer.mask_in_shadow: bool`
* `Spine_Animator.mask_in_shadow: bool`
* Spine animation APIs
  * `Spine_Animator.set_on_event()`
  * `Spine_Animator.set_on_animation_start()`
  * `Spine_Animator.set_on_animation_end()`
  * `Spine_Event_Data`
* Spine animator access
  * All Spine methods are now available directly on `Spine_Animator`
  * `.instance` is no longer required
* `Entity.set_name()`
* `Entity.compare_name(name: string) -> bool`
* Scene inventory and save APIs
  * Added inventory capacity APIs
  * Added auto-save APIs
* Voice and VOIP APIs
  * `voice_set_range(float)`
  * `voice_get_range()`
  * `Scene::voip_range`
* UIK
  * New API for building UIs
  * Docs are coming soon

</details>
{% endupdate %}

{% update date="2026-03-06" %}

## Protocol 41 - March 3rd, 2026

This protocol update improved CSL netcode performance dramatically and introduced new **Terrain and Tilemap editor tools and a built in agent to help with scripting and world building!**

<details>

<summary>New Features</summary>

* Terrain tool
  * Paint grasslands, oceans, shores, caves and more with broad high performance brush strokes
* Tilemap editor tool
  * Bring a tile set (or use one of ours) and create tiled maps using the new tilemap component
* Agent pane
  * Hooks into Claude Code or Codex-Cli and can build maps, write scripts, and design UI
* New MCP features
  * Tools for world building
  * Tools for reading game logs
  * Tools for adding full SFX from our catalog to your games!

</details>

<details>

<summary>API Changes</summary>

* Improved leaderboard culling APIs

</details>

<details>

<summary>Bug Fixes</summary>

* Major crash fixes & performance improvements!

</details>
{% endupdate %}

{% update date="2026-01-30" %}

## Protocol 40 - Feb 9th, 2026

This protocol update introduces CSL and makes major improvements to the editor workflow for new projects. Protocol 40 is expected to launch around Feb 3rd

<details>

<summary>New Features</summary>

* Adds support for our new game programming language. You'll see new experiences built with this soon!
* Voice chat quality and moderation accuracy improved
* Added chat spam prevention
* Core app features are now translated into 34 languages!
* Improved text rendering on low-end devices
* Android now supports deeplinks from web/push notifications into the app.

</details>

<details>

<summary>Editor Changes</summary>

* The editor now has you select a "game projects" directory at startup and will make any game there available to you\
  When creating a new game from Campfire, we now automatically fill in the ao.project with your game ID.
* Added saving progress bar to the top of the editor when saving
* Added in-editor asset search
* Assets in your project can now be rearranged in folders directly in the editor
* Improved project upload (zip) speed
* Launching the game for testing will use the latest version of the scene even if you haven't saved yet
* You can now change the scale of Sprite\_Renderers directly in editor
* You can now create and save custom layouts for editor panel positions
* The MCP server is now installed automatically
* CSL is now default for new projects. If you need C# you must remove csl: true from ao.project

</details>

<details>

<summary>API Changes</summary>

* Added C# Save.GetAllKeys()

</details>

<details>

<summary>Bug Fixes</summary>

* No major bug fixes this release

</details>
{% endupdate %}
{% endupdates %}
