For the complete documentation index, see llms.txt. This page is also available as Markdown.

Changelog

New updates and improvements

Protocol 46 - August 3rd, 2026 (Currently Nightly)

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.

Compatibility and Migration
  • 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

Runtime Tilemap API
  • 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, 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

  • Overlapping expanded wall rows now produce continuous wall masks instead of visible internal seams

UIDoc UI and Styling
  • 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 the hand-drawn Game UI kit

    • Add @import "game-ui-kit"; to use the built-in modal, button, tab, progress-bar, banner, porthole, item-slot, checkbox, and toggle styles and art

  • 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

New CSL APIs and Behavior
  • Live events

    • 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

    • Presenter ghosts are intentionally excluded from normal entity and component iteration

  • 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

C# API Changes
  • 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

  • Live events

    • Added LiveEvents.IsActive, IsLocalPlayerPresenting, PresenterCount, GetPresenter, and TryGetPresenterBySlot

    • LiveEventPresenter exposes slot, display name, speaking state, and a client-local ghost entity

    • Live-event ghosts remain directly usable but are hidden from normal scene and component enumeration

CSL Compiler, JSON, and Project Validation
  • 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

Live Events, Voice, and Player UI
  • 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

Editor and Developer Workflow
  • 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

Automation, Testing, and Diagnostics
  • 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

  • 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

Runtime, Platform, and Performance
  • 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

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.

Compatibility and Migration
  • 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

UIDoc Screen-Space UI
  • 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

Visual UIDoc Editor
  • 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

New CSL Gameplay and Rendering APIs
  • 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

Player and Runtime Changes
  • 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

CSL Compiler and Project Workflow
  • 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

C# API Changes
  • 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

Editor, Automation, and Testing
  • 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

Performance, Hosting, and Stability
  • 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

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.

Sync and Interpolation
  • 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

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

CSL Language and Compiler Changes
  • 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

Core API and Runtime Changes
  • 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

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.

Breaking CSL Changes
  • 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

Core API Breaks
  • 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

UIK Breaks
  • 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

Library and behavior changes
  • 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

Developer workflow
  • csl.exe <folder> now defaults to compile and run

  • Use csl.exe <folder> -no_run for compile-only behavior

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.

Breaking Changes
  • 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.parententity.get_parent()

    • entity.first_child / entity.last_childentity.get_first_child() / entity.get_last_child()

    • entity.next_sibling / entity.prev_siblingentity.get_next_sibling() / entity.get_prev_sibling()

    • entity.first_component / entity.last_componententity.get_first_component() / entity.get_last_component()

  • Component navigation fields were replaced with methods

    • component.prev_component_on_entitycomponent.get_prev_component_on_entity()

    • component.next_component_on_entitycomponent.get_next_component_on_entity()

  • Component state fields were replaced with accessors

    • component.enabledcomponent.get_enabled() / component.set_enabled()

  • Component iterator updates

    • next(ref Component_Iterator) was removed. Use .next() instead.

  • Effects system was restructured

    • entity.active_effectentity.get_active_effect() and now safely returns null when no effects exist

    • entity.first_effectentity.get_first_effect()

    • entity.last_effectentity.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

CSL Language Changes
  • 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: s32s64

  • switch cases now support multiple values and inclusive ranges

switch level {
    case 1, 2, 3: tier = .BEGINNER;
    case 4..10:   tier = .INTERMEDIATE;
    case 11..20, 25, 30..50: tier = .ADVANCED;
    default:      tier = .UNKNOWN;
}
Deprecations
  • 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.

New APIs
  • 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

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!

New Features
  • 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!

API Changes
  • Improved leaderboard culling APIs

Bug Fixes
  • Major crash fixes & performance improvements!

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

New Features
  • 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.

Editor Changes
  • 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

API Changes
  • Added C# Save.GetAllKeys()

Bug Fixes
  • No major bug fixes this release

Last updated