Changelog
Notes for 0.7.0.
Series
0.7
Highlights
- The launcher connects your AI assistant (Claude Code or another MCP client) to a project in one step, and upgrades an older project to this version in place, keeping a backup you can restore.
- Build bigger worlds in the editor: shape roads, plant whole areas with foliage presets, nest prefabs inside prefabs, and see particle effects play without pressing Play.
- Richer scenes: boats and anything floating leave wakes and spray, terrain rock draws arches, overhangs and cliffs, and a named look such as sunny midday sets the sky, sun and haze in one step.
- Characters come alive: imported skeletons from the common tools are recognised, faces blink and follow the voice, and props can ride on a bone.
- Make a kart race in minutes: a Kart starter project, a race HUD kit (countdown, positions, lap timer, minimap) and a 15-minute walkthrough; vehicles can also float and drive on water.
Migration
- Since 0.6.0 the engine ships no starter sounds, so a 0.5 project whose audio assets use builtin:sfx/, builtin:music/, builtin:ambient/ or builtin:voice/ paths does not open, and project migrate refused it until this release (asset-builtin-unknown). The 0.6.0 notes left this out. Fix: run
argus project migrate --applyon the project. It points each of those sounds at a placeholder file of the project's own (assets/audio/retired-builtin/… beside the scene: a short beep, or silence for music and ambient), lists every one in its report, and never overwrites a file that is already there. Replace each placeholder with a real sound;argus project migrate --restoreundoes the change. A prefab that uses one is still refused: give it a sound file of your own (the make-your-own-sounds recipe makes one). Meshes such as builtin:cube are not affected. - NPC types compile in TypeScript:
npc({...})runs the compiler when the module is evaluated and hands the engine a compact program (__npcProgram), which the engine checks (indices, bytecode stack bounds) and reads. The engine no longer links the NPC IR reader or compiler, so a module built by @argus/gameplay before 0.2.0 (IR only) is a script error that names the version to rebuild with. Fix: projects from source need nothing (the engine bundles each behaviour against its own @argus/gameplay when it loads it); a game exported earlier, whose bundled behaviours came from @argus/gameplay before 0.2.0, must be exported again with this engine. A type with a mistake now fails where its module is evaluated, with the same messages.
Known
- Windows only, and the installer and engine are not code-signed yet: Windows shows "Windows protected your PC". Choose More info, then Run anyway, after checking the installer's SHA-256.
- Projects from 0.6 open as they are (the project format is unchanged). A project from 0.5 that used the starter sounds opens after
argus project migrate --apply: see Migrating from 0.6. A game exported with 0.6 whose NPCs use TypeScript types must be exported again: see Migrating from 0.6. - Sign-in is not open to everyone yet; a tester token from your invite still works.
- The editor's Log tab is noisy on every Play, and shows "423 busy" lines when your AI started the editor. Both are harmless.
- See talosengine.ai/known-issues/ for the full list, each with a way round it.
Sections
added
- {"area":"editor","text":"A component's menu in the Details panel can now remove it, reset it to defaults, and copy and paste its values (also across a multi-selection). Rows whose value differs from the default get a reset arrow, and the entity header has an editable name and tags."}
- {"area":"editor","text":"Content browser tiles can be renamed (F2), deleted (Delete, after a list of what uses the file), duplicated (Ctrl+D), copied as a path and traced with Find references; a rename rewrites every reference. Right-click now selects the tile."}
- {"area":"editor","text":"A component's asset fields (a mesh's model and material, audio, a script's module, terrain and road files) are now slots in Details: pick from a searchable list of the project's assets, drop a Content tile on them, Browse to the file, or clear an optional one. A tile of the wrong kind is refused with the reason."}
- {"area":"editor","text":"Select a generated house, street or town and Details now says how to vary it: the settings your AI assistant can use (storeys, style, which way the gable faces, roof pitch, and for towns the rows settings), each with a value to start from and what it does on hover. The Building and Street entries in the Create menu point to it."}
- {"area":"editor","text":"Every component in the Details panel now has editable fields: lights, cameras, colliders, rigid bodies, spawns, particles and the rest show a drag value, checkbox, dropdown or colour picker for each setting, and editing several selected entities changes the settings they share together."}
- {"area":"editor","text":"Dropping a model, sound or font from the file manager onto the editor window imports it, with a Drop to import hint while it is over the window. Several files import one after another."}
- {"area":"editor","text":"A read-only Animator graph tab in the editor's drawer shows the selected entity's states, transitions, layers, parameters and event windows, and during Play lights the state that is playing on each lane."}
- {"area":"editor","text":"The foliage brush shows its radius and soft edge on the ground under the pointer, has strength and falloff sliders, a layer picker and [ ] / Shift+[ ] keys, and a Shift-erase no longer sticks; tile painting gets a Fill (bucket) tool and an outline of the cell under the pointer."}
- {"area":"editor","text":"The Animator section in Details lists an entity's clips (length, loop, root motion, events and windows) and scrubs or plays one in the authoring viewport without starting Play; Stop restores the authored pose and the scene is never touched."}
- {"area":"editor","text":"Create ▸ Building and Create ▸ Street make a house, or a short street of six houses along a road, from the engine's own building kit in one click, where you are looking, with no assistant needed."}
- {"area":"editor","text":"A Create menu in the editor's top bar adds a terrain, a road or a foliage brush without selecting anything first; a foliage stroke over no ground now says why it painted nothing."}
- {"area":"editor","text":"The editor imports FBX models: Import model..., a file dropped on the window and Place on an .fbx or .obj in the Content browser all start the same import. An FBX is converted to a GLB (metres, Y-up, base colour and normal textures, skeleton and animation kept) by your own Blender running headless in the background, with progress and a Cancel that also ends Blender (and quitting the editor does); if Blender is not installed the editor says to install it or set the ARGUS_BLENDER variable to its program. OBJ files import as before, now also from the file picker."}
- {"area":"editor","text":"Particle effects now play in the editing view without pressing Play: the selected effect loops, and View > Preview effects turns it off."}
- {"area":"editor","text":"The transform gizmo works during Play with the view ejected: dragging moves the running object from where it is now, as a live edit that Undo, Keep changes and session replays treat like any Details edit. The Keep changes bar now stays put for the whole ejected Play, so the view no longer jumps at the first live edit."}
- {"area":"editor","text":"Import… (and dropping a file on the editor) now takes a picture: a
.pngor.jpgis checked with the engine's own texture decoder and copied into the scene'sassets/folder, ready to use as a material's Base Color Texture. Before, a picture was refused, so there was no way to bring an image into a project to texture a model with."} - {"area":"editor","text":"You can now edit while the game runs: with Play's view ejected, any Details field of any entity (children included), component add or remove, World Settings and Undo reach the running world between two ticks, are recorded on the sim clock and replay exactly, and are gone at Stop unless you press Keep changes; behaviour files saved during Play are compiled and swapped in without stopping it (state kept, a file that does not compile leaves the old code running)."}
- {"area":"editor","text":"Importing a picture with a model selected puts it on that model: the editor makes a material beside the picture that uses it, and sets that material on the selected mesh, all as one step that Undo takes back."}
- {"area":"editor","text":"The editor records that a project really opened (its first frame was shown) in the project's state folder (editor/opened.json), so the launcher can tell a project that opened from an editor that died at once."}
- {"area":"editor","text":"Roads can be shaped in the editor: select one and press Edit points in Details to drag its points, Ctrl+click to add one or Delete to remove one (each one undo step), and set its width and kerbs there. A road made in the editor is drawn at once, Focus frames the whole road, Details says what is wrong with a road file that will not build, and
argus validatefails on one, naming the field."} - {"area":"editor","text":"A selected sprite's Details has a sheet slicer and a clip editor. Slice into frames cuts a picture by columns and rows, one frame per cell, skipping empty cells and cells that are frames already. Clips can be added, renamed, removed, set to play from load, and given an fps, a loop and per-frame seconds; click a frame to add it to the clip, and move or remove a clip's frames. The clip being edited previews as the engine plays it. Each change is one undo step, and what the sprite can't hold is refused with the reason."}
- {"area":"editor","text":"The editor can sculpt and paint terrain: select a terrain, turn on the terrain brush in Details, and drag on the viewport to raise, lower, smooth, flatten or paint a layer. Each stroke is one undo step, and Details now shows the terrain's size, layers and op stack."}
- {"area":"editor","text":"A terrain made with Create > Terrain now has a ground layer, so Paint works on it straight away; the ground looks as it did. The terrain's Details panel can add a layer (any material in the project) and remove one. Removing is refused while it would change the ground: the first layer, a layer an op names, or a layer that is painted or sits before a painted one. Each change is one undo step, and the viewport draws the new layer list at once."}
- {"area":"editor","text":"World Settings shows when a scene is over its triangle budget: under Budgets ▸ Triangles a line says how many triangles the scene draws against the budget, and one click sets a budget that holds it (Undo takes it back)."}
- {"area":"editor","text":"A script error during Play now shows as red error and warning counts on the Output Log tab and the status bar's Log button, and raises one toast with an Open log button on the run's first error. Log rows can open their file at the failing line, the Play menu has a Pause on error switch, and Play's session line is now Verbose with a plain \"Play started in N ms\" line instead."}
- {"area":"editor","text":"A new project opens with a dismissible Getting started card for its type (3D or 2D) showing the navigation, tool and Play keys; Help > Getting started brings it back and Editor Preferences can turn it off for good."}
- {"area":"editor","text":"Foliage layers on instanced meshes: Paint as foliage makes a layer from a mesh, and a brush paints and erases plants on the ground (deterministic, one undo step per stroke); argus scene instance --foliage gathers generated plants under a layer."}
- {"area":"editor","text":"Import can give a character with no skeleton (one rigid mesh, as AI model generators and scans make them) a simple body rig: tick \"Give it a simple body rig\", or pass bodyRig: true to asset.import. The copy gets five joints up its middle and nine body clips an Animator can play: Idle, LeanLeft, LeanRight, Punch, Throw, ThrowBack, PointLeft, PointRight and Cheer. Your file is not changed, and an import without the option is exactly as before."}
- {"area":"editor","text":"Importing a model with a texture over 4096 pixels a side (an 8192 picture is 268 MB loaded) now warns (
large-texture), naming the picture, its size, what the model's textures take and the scene texture budget (meta.budgets.textureMB) they need: a model larger than that budget does not load at all. Nothing is downsized."} - {"area":"editor","text":"Instanced meshes in the editor: Make instanced turns selected plain meshes into one instanced mesh, a click selects one instance, and the gizmo, Duplicate, Break out and Delete edit it, each one undo step."}
- {"area":"editor","text":"New project has a Kart starter (
project.createwithtemplate: \"kart\"): the Kart Starter sample, embedded fromsamples/kart-starterso the two cannot drift apart, on a flat 256 m grass terrain (terrain/ground.terrain.json) in place of the sample's box of ground.foliage.presetplants on it with no terrain steps first, and thearcade-kartpreset slows on it off the road. The web build has no terrain yet, so such a project draws no ground in the browser; the sample itself keeps its box and plays there as before."} - {"area":"editor","text":"The editor's control endpoint now answers on the launcher. Started with
--control-portand no project, the editor servescontrol,state,controls,eventsandlogthere, so an agent can walk New project and Open project the way a person does; routes that need a project answer 409no-project. The endpoint moves on the same port to the project the launcher opens, writescontrol.jsonthere, and returns to the launcher when the project closes."} - {"area":"editor","text":"The material panel edits every field of a plain material (extensions, UV transform, layer mask), adds, reorders and removes layers, and shows the contract's problems with their codes beside the fields; New Material in the Content browser makes a blank or preset material and opens it."}
- {"area":"editor","text":"A material in the Library tab shows small badges from what the library records about it: its tiling in metres, the largest texture size, the maps it carries, and cut-out or two-sided only when true; the selected hit lists the same fields in full, with anything not recorded shown as \"not recorded\" rather than \"no\"."}
- {"area":"editor","text":"The Library tab can filter by the
materialclass, and a material hit offers Use on selection: it brings the GLB into the project when it is not there and sets the selected mesh's material to it as one undo step (disabled, with the reason on hover, when no single mesh is selected). The material panel gets Find in library, which opens the Library tab on materials searching for the open material's name, and opening an imported library material (a GLB) says so in one line instead of offering edits."} - {"area":"editor","text":"The material panel paints a layer's mask: a Paint mask toggle on each layer opens a canvas of the material's
layerMasktexture with a radius, strength and falloff brush (Shift or Erase lowers it), one undo step per stroke, and a Create mask button that makes the 512 or 1024 px PNG when the material has none; only the layer's own channel of the file changes, and the file is written atomically so the preview and a running Play reload it."} - {"area":"editor","text":"The material panel has a live preview tile (sphere, cube or plane, standard or HD) drawn by the engine's material capture on a background thread; it redraws shortly after each edit, when a layer's or texture's file changes, and shows the engine's reason when a material is refused."}
- {"area":"editor","text":"Right-click menus on Outliner rows and in the viewport, and the Edit menu, now list Cut, Copy, Paste, Duplicate, Delete, Rename, Frame Selected and Hide, and the View menu lists the projections, view modes and overlays. Menu shortcuts follow your key bindings, Help has a Keyboard Shortcuts item, and Report a bug and Request a feature have shortcuts (Ctrl+Shift+F1 and Ctrl+Shift+F2)."}
- {"area":"editor","text":"Music generation: make songs for your game with Mureka on your own API key, off by default per project. The editor (Content Browser > Generate music) and agents ask before each paid song and show its price, within the project's spend cap. You can also import tracks you downloaded from Suno, kept untouched with their provenance and your plan's licence. Use as scene music loops a track in the scene, with optional loop points."}
- {"area":"editor","text":"The editor now works with prefabs inside prefabs: nested instances are marked in the Outliner, a click picks the outermost instance and clicking the same spot again goes one level deeper (Alt+click goes straight to the part), and Edit Prefab shows a car's wheels and opens them with a breadcrumb. Create Prefab and Place work with nested prefabs and refuse a prefab that would contain itself."}
- {"area":"editor","text":"Prefabs that contain other prefabs now work everywhere: an edit to an inner prefab reloads a running scene and the open editor, and the editor's counts and Edit Prefab bar include prefabs nested inside others. Scripts can spawn a nested prefab (with nested override keys), and an exported game carries and spawns them."}
- {"area":"editor","text":"The Add component list and each component's title in Details show a Beta or Experimental badge from the engine's feature list, and pointing at one says what the label means."}
- {"area":"editor","text":"The Add component list has Terrain, Road and Foliage buttons: a flat 128 m terrain centred on the origin and a short road across it, each in one step, and a foliage layer that paints copies of the selected object's model with a brush."}
- {"area":"editor","text":"Opening a plain material (a .material.json without a shader) now shows a panel with its base colour, metallic, roughness, emissive, alpha and texture slots, instead of saying there is nothing to show. Changes are written to the file as you make them, the viewport redraws live, and the panel has its own Undo and Redo."}
- {"area":"editor","text":"Details has an Overrides list on every prefab instance. Apply on an override of a nested part asks which prefab takes it (the car or the wheel), says how many instances, scenes and prefabs that changes, and is one undo step. Rows a prefab sets are bold and say who set them; entities added to an instance can be moved into its prefab."}
- {"area":"editor","text":"Unpack Prefab turns a prefab instance into plain entities in one undo step, from Details, the right-click menus and the agent's prefab tool. A prefab nested inside it (a wheel in a car) stays an instance unless you choose Unpack Prefab Completely; the parts get ids without slashes (
car-1/roofbecomescar-1-roof) and everything that pointed at them follows."} - {"area":"editor","text":"The control API can start the Presentation view framed on a camera bookmark or looking through a camera entity (
POST /v1/do {\"do\":\"presentation\",\"bookmark\":2}or{\"camera\":\"<entity id>\"}), so a recording frames a large scene instead of orbiting all of it. F11 still orbits."} - {"area":"editor","text":"The asset library CLI has a process verb that runs a provider's Smart UV, auto-rig (five skeleton presets, mapped to the canonical humanoid) or retopology step on any mesh in the project with your own key, and measures the result in the quality gate. A dry run shows the requests and price without sending anything."}
- {"area":"editor","text":"A vehicle's preset fields (drivetrain, drift, chassis and the rest) now show in Details as rows with the preset's values; editing one writes only that override, and its reset arrow goes back to the preset."}
- {"area":"editor","text":"Show ▸ Game UI controls whether the game's own screens (a HUD, a menu, a loading curtain a behaviour puts up) are drawn over the authoring view. It is off by default, so a sample's start menu no longer covers the level when you open it and doesn't look like a game already running. Turn it on to see the screens in place. Play always draws them, and the UI preview draws them whatever the setting.
set-viewandeditor.statecall itgameUi."} - {"area":"engine","text":"Atmosphere skies take an aerialScale (0 to 100, default 1) that thickens HD's aerial perspective as if every distance were that many times longer, so a world a few kilometres across can show the layered blue depth of a real mountain range; the sky itself does not change."}
- {"area":"engine","text":"A scene can declare its air (meta.environment.air): its density and a wind with optional gusts. A buoyancy body out of the water is then buoyed by the air it displaces and dragged against the wind, so the same component floats a gas envelope in the sky as a hull on the sea; a new buoyancy angularDrag damps a floating body's spin."}
- {"area":"engine","text":"Animation events can now be windows: an event with
untilopens and closes with begin and end events that are always delivered as a pair, even when the clip is crossfaded out, interrupted, seeked or removed, and scripts can askctx.animator.window(name). Events can also be placed byframeand carry adataobject."} - {"area":"engine","text":"Animators can declare layers: a second playback of the same states over part of the body (a bone mask), either replacing it or adding to it, so a character can swing or lean while its legs keep running. Each layer fires its own clips' animation events and windows, with the layer's name in the event. (API since 0.7.0)"}
- {"area":"engine","text":"Motion warping:
ctx.animator.warp({ to, by, maxScale })re-aims and scales a root-motion state's ground travel so the character arrives attowhen the clip reaches clip timeby, with the collision, vertical and yaw motion unchanged; a state change clears it."} - {"area":"engine","text":"Vehicle preset
arcade-kart: thekartwith itshandling,recovery,contactandoffRoadassists on at their defaults, so an arcade kart (drift tiers and boosts, landing assist, respawn, post-hit assist) is one preset name with no script. Presets can now carry those four blocks, merged field by field under the component's own;kartand the other presets are unchanged. See docs/VEHICLES.md §3."} - {"area":"engine","text":"The asset gate's new motion command judges a skinned GLB's clips from their motion: loop seam, foot slide, one-frame pops and snaps, root jumps, bone coverage on the canonical humanoid, bad keys, idle drift and tagged speed, with a Next: for every reject. Lengths are a share of the rig's height, so centimetre files are judged like metre ones."}
- {"area":"engine","text":"The HD renderer can hand a terrain material the water's edge (each lake's, river's and the sea's level and how far up its bank stays wet), for wet banks."}
- {"area":"engine","text":"Entities can follow a bone of an animated character with the new attach component. An attached entity with a trigger collider is a sensor: it reports what it overlaps along the path it swung through each tick as overlap events, so a fast swing or a low tick rate still hits what it passes, optionally only while an animation window is open, and scripts can switch it with ctx.world.setSensor and read it with ctx.world.overlaps. Scripts can also ask ctx.world.overlap for the bodies a sphere, capsule or box touches."}
- {"area":"engine","text":"New theatre live command: watches a project while agents build it, without ever writing to it, and records what it sees with the same camera and arrival animations as a replay; theatre plan and render can also play a game with one of its own self-test scenarios before showing what it built."}
- {"area":"engine","text":"Build Theatre renders now come with an overlay (captions taken from the agents' feed, the run clock, build-phase chips, agent name tags and an end card, kept inside each aspect's safe zones) and a sound layer of soft pops, whooshes and a closing chime; tools/theatre/compose.sh turns a render into a clean clip and a captioned clip, and theatre overlay re-captions without re-rendering."}
- {"area":"engine","text":"New
theatre plancommand: reads a timelapse snapshot store and an activity feed, and writes a cut plan (cut.json) that gives each stretch of the build screen time by how much changed, with the run clock and captions taken from the feed."} - {"area":"engine","text":"New
theatre rendercommand: records a planned build cut to frames in one run, with an automatic camera that frames each burst of change for the chosen aspect (16:9, 9:16 or 1:1, no letterbox), new objects that drop in instead of popping, and a closing orbit of the finished scene."} - {"area":"engine","text":"theatre plan --runtime-diff and theatre render --runtime show games that build their world in code (tiles spawned by scripts) growing, not only their scene files; stretches without an agent feed are captioned with what changed, and tools/timelapse/feed.mjs turns agent transcripts into a caption feed."}
- {"area":"engine","text":"A generated building's door can ask to be an open doorway (
open: true), picked from the kit's door pieces tagged open, so a player can walk in; the engine's own kit tags its doorways."} - {"area":"engine","text":"A networked session can set HostConfig::call_depth_limit (NETWORK_CALL_DEPTH, 256) so a deep recursion throws at the same call in the browser and natively, instead of at each engine's own stack limit."}
- {"area":"engine","text":"ctx.camera.shake(amplitude, seconds?, frequency?) jolts the drawn view with a deterministic trauma-style decay and reports it as camera.shake in GET /feel; the controller component takes accel, decel and turnRate; a held lock-on rig ignores look input."}
- {"area":"engine","text":"The foliage scene manifest's canopy infill can fill a ring about the viewpoint (r_min_m, r_max_m, far_weight): new trees spread over the whole ring up to 6 km, across all tree layers of the mask, instead of the nearest cells only. Off by default and pay-for-use: a manifest that does not set it places exactly as before."}
- {"area":"engine","text":"
scene_capturemanifests takequalityOverrides(any quality overrides, e.g.{\"virtualGeometry\": {\"mode\": \"off\"}}) on top of the preset, so a virtual-geometry or other knob A/B is one manifest line.results.jsongainsquality_resolved(preset, resolved virtual-geometry knobs, diagnostics) to show which mode ran."} - {"area":"engine","text":"A mesh's collider mode:
colliderMode\"simple\" (one capsule: a generated plant's trunk, else the model's bounds), \"full\" (its exact shape, as before) or \"none\", on the mesh, the asset ormeta.physics; a generated plant is \"simple\" by default. The oldcollidestill reads as before; disagreeing withcolliderModeis the warningmesh-collide-conflict."} - {"area":"engine","text":"Scenes can turn on contact ambient occlusion in the standard renderer (render.ao: strength, radius, fadeEnd), which darkens creases and the ground where objects meet it. It is off unless a scene asks for it, so other scenes draw exactly as before."}
- {"area":"engine","text":"A couch join screen for local co-op: up to four slots that fill as players join, show each player's device, let them ready up or leave, and start the game once everyone seated is ready."}
- {"area":"engine","text":"Co-op games can seat a player who has no device on this machine:
ctx.players.join(\"remote\"). Their input arrives as frames keyed by player number, from a replay, fromPOST /input(which now takes\"player\": nin place of\"entity\"), or in-process. They join, leave, bind and raise the same events as a local player. Menus now read players 2 to 4 from the same input state as player 1. Before, a replay of player 2 pressing a menu button pressed nothing on playback; now it presses it on the same tick. A replay in ameta.playersscene also records which player each input row was (\"pl\"), and a playback gives the row to that player's entity wherever it sits. Buttons held across a context switch are recorded as such (\"c\"), so a replayed Start that opens a pause menu no longer shuts it on the same press. Older files still play as before."} - {"area":"engine","text":"Ground cover layers can vary in patches: an optional patches block (scaleM 0.5 to 60, value, hueDeg, height, density) varies each layer's colour, hue, blade height and density at 5 to 30 m by a world-position field the blades and the ground carpet share, and carpetPull sets how far the carpet pulls the terrain toward the layer's hue (default 0.4; more hides tan litter). Without them a layer draws exactly as before. Patches can also carry contrast (clumps and gaps), a heightRange, dry patches with a strawColor and a strawShare of straw blades, and scaleM down to 0.5 m. The built-in meadow preset now carries Flora's palette (patches scaleM 12, contrast 0.9, heightRange 0.35 to 1.9, dry 0.5, strawShare 0.2, hueDeg 15, value 0.4, density 0.3, and carpetPull 0.65), so a terrain that names the meadow, or the default meadow-forest, gets varied patches without listing any. The preset's records are pinned by a golden tile, so a later palette change is a recorded change, not a silent one."}
- {"area":"engine","text":"A game can shade the terrain's ground cover under its tree crowns: World::set_cover_shade thins the meadow under them and brings in the forest floor. Without the call the cover is unchanged."}
- {"area":"engine","text":"A snapshot carries the crowd (crowd: each navagent by scene id, and the Rust crowd's exact runtime), so a world restored from it, a late joiner's included, walks its navagents on exactly as the run it came from; Detour's crowd is put back from the summaries. The runtime names its navmesh and is refused over another; a restore before the crowd is built waits for it; the restore report counts
crowd_joinedandcrowd_deferred."} - {"area":"engine","text":"Characters can have an alive face: a
facecomponent adds blinks, eye saccades, brows and cheeks that follow the voice (withlipsync), and head sway and nods, found by the model's ARKit shape names. It is seeded, so the same scene always moves the same way."} - {"area":"engine","text":"GET /feel gains
particles(every ctx.particles.emit burst, plus each particles emitter's emitted count) andhapticssections andcamera.pitch;ctx.input.rumble(strength, seconds)/(low, high, seconds)shakes a gamepad where the build and device support force feedback and is recorded on /feel either way, so a headless run can measure it."} - {"area":"engine","text":"critic.play feel: the response and movement probes write their numbers into verdict.feel.metrics beside the others, so a genre profile scores every probe; actions.invulnMs measures a dodge's invulnerability (a window named invuln or iframes, or playtest.invulnWindow); the impact probe reads particles and rumble by their seq."}
- {"area":"engine","text":"critic.play takes profile (melee-duel, third-person-action, platformer-3d, kart-racer, auto): the feel metrics are scored against a genre profile into verdict.feel.profile with a diagnosis of levers per failing row, and scripts/feel/loop.mjs keeps the tuning rounds."}
- {"area":"engine","text":"critic.play feel gains two probes, response (ticks and ms from each input action's press to its first bus event, animator change, pose change, velocity change and camera change; dead and slow buttons) and movement (walker accel, stop, turn rate, top speed and foot slide; jump height, apex, air control, buffer and coyote time; a vehicle's 0-to-top, steering and braking), with seven feel/* codes, and the same probe names on the critic.play feel parameter"}
- {"area":"engine","text":"Plants can carry a per-vertex crown occlusion (glTF
_FLORA_OCCLUSION, flagged byextras.flora.occlusionAttr) that darkens only the indirect light and only where there is no ray-traced GI, so a canopy is no longer darkened twice on tiers that have GI; the standard renderer applies it to the vertex colour, and files without the flag draw exactly as before."} - {"area":"engine","text":"Two new plant species for the forest floor: stump (a sawn or snapped trunk with surface roots) and log (a fallen trunk lying on the ground with broken limb stubs), both with cut faces, weathered bark and moss, plus four ready-made templates."}
- {"area":"engine","text":"A new litter plant species: a flat patch of fallen twigs, cones and dead brown leaves for the forest floor, with conifer and broadleaf templates."}
- {"area":"engine","text":"Procedural rocks can carry moss: patches on their upward-facing surfaces, set per rock with a moss amount (off by default)."}
- {"area":"engine","text":"New plant templates for the forest understory: a young fir, birch and oak sapling, and an upright multi-stem understory bush that fills the 1-2.5 m layer under trees."}
- {"area":"engine","text":"A new vine plant species: ivy-like stems climbing a trunk or post of a given radius, leaves facing out and thinning toward the top, with an Ivy template."}
- {"area":"engine","text":"Fog preset
aerial: faint depth for a 0.3-1 km scene (20 km visibility, thinning within about 250 m of height, capped at half). Under a panorama sky, where HD has no physical aerial perspective, it is the depth cue. Additive: scenes that don't name it are unchanged."} - {"area":"engine","text":"Fog can be named (light-haze, valley-mist, morning-mist, dense) or set by visibility in metres, and the standard renderer now fogs the sky toward the horizon in the fog's colour, which defaults to the sky's horizon."}
- {"area":"engine","text":"Ground cover layers can name a scanned material set (
material, orgroundCover.setsby layer id): acover.jsonwith a blade colour ramp, roughness, translucency and petal palettes by flowerspecies, replacing the layer's procedural colours, which stay the fallback. A missing or broken set is reported once and the layer keeps its own colours. New per-layerroughnessandtranslucencyfields. Small crowns (shrubs under about 2.5 m) keep more of their light, so a shrub no longer reads black at a distance. Flora format 16."} - {"area":"engine","text":"Generated plants take a leaf and bark colour from their recipe: materials.leafTint and materials.barkTint, each {hue, saturation, value}, shift the colour at cook time, for example {\"saturation\": 0.6, \"value\": 0.8} for a duller, darker green."}
- {"area":"engine","text":"Foliage presets as data:
meadow,roadside-verge,pine-forestandbroadleaf-wood, each a set of terrain scatter ops (existing fields only) with its ground-cover preset and a budget over a 200 m square sized for a 4 ms frame. The verge keeps shrubs 2 m and trees 8 m off the roads."} - {"area":"engine","text":"Plants take real material sets:
materials.barkandmaterials.leafin a foliage recipe can name a project folder of scanned PBR maps (bark albedo, normal, roughness and ambient occlusion; a leaf atlas with its alpha, normal, roughness and translucency), and a trunk's texture now follows its circumference instead of stretching as it thins. Tree crowns are darker inside and brighter at the rim, leaves vary in hue and value from twig to twig, the default leaf colours are olive and yellow-greens, and leaves have a little sheen."} - {"area":"engine","text":"UI stylesheets take
font-variant-numeric: normal | tabular-nums.tabular-numsasks the font for equal-width digits (OpenTypetnum), so a race timer or score keeps its width as it counts. A font withouttnumdraws its usual digits, silently. Absent, nothing changes."} - {"area":"engine","text":"Forest scatter layers close their canopy near the camera by filling gaps with more trees of the same mix, and stand in strata by default: saplings, a shrub layer, ferns and a leaf-litter ground cover. A jungle plant palette for islands and coasts is built in."}
- {"area":"engine","text":"A game window goes fullscreen with F11 or Alt+Enter, and back the same way (borderless, on the window's monitor). Enter on its own stays the game's."}
- {"area":"engine","text":"
ARGUS_GPU_TIMING=everytimes the GPU on every frame for the whole run, for measurements such as A/Bs. Without it, GPU timing may drop to 1 frame in 4 to keep its own cost down, and it can choose differently from run to run. The Perfetto export's GPU row now says which rate the run used, and that a frame without GPU spans was not measured."} - {"area":"engine","text":"
meta.render.exposureMode: \"auto\"lets HD meter every frame and adapt like an eye, so shadowed streets and sunlit views both read;exposurethen brightens or darkens the metered result. Absent ormanualkeeps today's fixed exposure."} - {"area":"engine","text":"HD draws user shader materials on virtual geometry: a mesh the quality makes virtual geometry keeps a G-buffer family's material (opaque or mask, lit or unlit, no vertex()) and the family's own surface() shades it, where such a submesh used to stay on the raster path. One merge pipeline per family a virtual-geometry mesh uses, one full-screen pass per family in view; forward and vertex() families keep their meshes raster."}
- {"area":"engine","text":"The stock HUD looks like a game's HUD instead of debug text: each row is a readable panel with a label and its value (
Lap 2,Timer 0:06.0), andctx.hud.set(field, value, { label, unit, decimals })gives a field its own label, a unit and fixed decimals:ctx.hud.set(\"speed\", 92, { unit: \"km/h\" })showsSpeed 92 km/h. Calls without options still work, and a scene'smeta.hudstyle still wins."} - {"area":"engine","text":"The impact probe says when a pressed button opened its active window without touching anything, instead of silently leaving its hit-stop metric out."}
- {"area":"engine","text":"
ctx.input.rebind(action, binding, context?)andctx.input.bindings(action, context?)take an optional context, so a settings screen running in amenucontext can show and remap gameplay's keys without switching to gameplay first (input.rebind(\"jump\", \"K\", \"gameplay\")). Without it they mean the live context, as before. A context the map does not have is refused withinput-unknown-context."} - {"area":"engine","text":"Instanced meshes and foliage layers can collide as one collider per 64 m cell instead of one per instance (collisionLayout \"cells\"), for far less memory in large forests; rays and shape casts give the same answers."}
- {"area":"engine","text":"Instanced meshes: an instancedMesh component draws one mesh at many places from a .instances file (one entity instead of thousands, a stable id per instance, ctx.world.instances in scripts), and argus scene instance turns groups of identical static mesh entities into one."}
- {"area":"engine","text":"Instanced mesh files can be written with 16-bit columns, about 45% smaller;
scene encode-instancesrewrites them and prints the bytes before and after. Positions stay within half a step of their spread (1.6 cm over 2 km), and existing files load and save unchanged."} - {"area":"engine","text":"A building kit's kit.json may name the collider its pieces start with when imported by hand in the editor; a piece may name its own. The engine's own kit names box, with trimesh for its doors, doorways and gates, so its walls are solid and its openings stay open as soon as they are imported."}
- {"area":"engine","text":"A material layer can multiply instead of mix: the new blend key (\"mix\" by default, or \"multiply\") makes the layer's base colour darken the colour below by the mask, so a wet or dirty film keeps the surface's hue. Only the base colour changes; normal, roughness and the rest still mix. Files without blend draw as before."}
- {"area":"engine","text":"Material-file layers and terrain-file layers can have a soft, broken-up edge where they meet what is below them:
\"edgeWidth\": 0.6, \"edgeNoise\": 0.4, \"edgeNoiseM\": 0.5on a layer.edgeWidth(0 to 1) softens the edge, from the hard switch-over the blend's contrast and heights make (0) to a smooth fade along the mask (1), so snow or dust can thin out instead of stopping at a hard line; where the mask is full the layer still covers.edgeNoise(0 to 1) moves the edge with deterministic noise, andedgeNoiseMsets the noise's size in metres. On a mesh the noise is in the object's space, so it moves with the object; on the terrain it is in world space, and where two terrain layers meet, the wider width and the stronger noise of the pair apply. Without the keys every layer looks exactly as before. HD only for now: the standard renderer draws material layers with their plain edge (it nameslayer edgeamong what it does not draw), and draws terrain edges the same way HD does."} - {"area":"engine","text":"Material layers can follow the surface's height: a layer's new heightBlend makes its edge favour the higher surface, so moss settles between cobbles and snow on top of bumps. The standard renderer now draws material layers too (it drew the base material only), with the same blend as HD."}
- {"area":"engine","text":"A material file's layer can take its coverage from the mesh itself:
\"maskFrom\": { \"heightM\": [0, 0.9], \"facing\": \"up\" }.heightMlays the layer from the bottom of the mesh's bounds up to the first height (metres, at the object's scale) and fades it out by the second, for dirt and splash rising up wall bases;facinglays it only on surfaces facing up (dust, moss on tops) or down (grime under overhangs). The result multiplies the layer's mask channel, so a building kit without mask textures or vertex colours gets wear from one shared grime material, andedgeWidth/edgeNoisebreak its edge up. WithoutmaskFroma layer looks exactly as before. HD only: the standard renderer blends such a layer by its mask alone and says so once per material (render.standard.layer-mask-from-ignored). Virtual-geometry meshes are rebuilt once on first load (their build version moved, to carry the bounds' bottom)."} - {"area":"engine","text":"Four new material presets for layers, moss, wet, dirt and snow, that need no texture maps, so a layered material works with nothing but presets."}
- {"area":"engine","text":"Characters can lip-sync: a
lipsynccomponent moves a face's mouth shapes with the voice itsaudiocomponent plays, from the line's loudness or from avisemestrack (new asset kind) in time with the voice.argus-visemeswrites a track from a line's text."} - {"area":"engine","text":"Couch co-op: a scene can seat up to four local players (meta.players), each on their own gamepad, the keyboard, or half of a split keyboard, each driving their own entity. Players join by pressing a button, ctx.players lists and binds them, and replays reproduce every player."}
- {"area":"engine","text":"
meta.render.look.shoulder(0..1) rolls highlights off in HD: after the tonemapper, display luminance above 0.45 is compressed with a soft knee and colour kept, so bright skies and sunlit walls stop clipping (a full white ends at 1 - 0.275 x shoulder). Absent or 0 is today's frame, byte for byte."} - {"area":"engine","text":"A scene can soften the AgX toe with
meta.render.look.toe(0 to 1). It lifts dark tones before the curve (up to a stop at 1) while mid grey moves about 0.07 EV and highlights not at all, so shade reads less crushed. Absent or 0 draws exactly what it drew before, and old scenes save the same bytes. HD only; the standard renderer ignores it."} - {"area":"engine","text":"New
material checkcommand: measures a material's (or every terrain layer's) mean linear albedo and roughness and says whether they fall in the range real grass, soil, rock, sand or snow does, with the factor that would bring the albedo into range."} - {"area":"engine","text":"A material layer can take
\"edgeStreakM\"(metres, above 0): the wavelength of its edge noise along the object's up axis, apart fromedgeNoiseM. A long value stretches the noise into vertical streaks, so a coverage edge runs down the surface like rain or grime drips. It does nothing withoutedgeNoiseabove 0 (amaterial-field-ignoredwarning). HD only; only a material that writes it compiles the extra code, and a file without it resolves, draws and compiles exactly as before."} - {"area":"engine","text":"A material layer's maskFrom takes ao, convexity and concavity: wear terms from signals the engine bakes per vertex from the mesh's own geometry (inner corners, outer edges, creases), with no texture needed. A layer still reads one wear signal."}
- {"area":"engine","text":"A material layer's
maskFromcan measureheightMfrom the building instead of each piece:\"heightFrom\": \"root\"measures from the origin of the mesh's topmost ancestor (a generated building's ground line), so grime rises from the foot of a kit house rather than banding at every storey. Absent (or\"mesh\") is the per-mesh height of before, byte for byte. The layers of one material must agree (material-height-from-mixed). HD."} - {"area":"engine","text":"A material layer's
maskFromcan take a wear term from the material's own maps:\"edge\": [lo, hi]follows how far the normal map tilts the surface (the bevels of a trim sheet: worn edges and corners),\"cavity\": [lo, hi]follows 1 - its occlusion (joints and crevices). One per layer (material-mask-from-wear-both); without the map it reads, the term does nothing (material-field-ignored). Compiled only into the variants of a material that has one (LAYER_WEAR); a file without them draws exactly as before. HD."} - {"area":"engine","text":"A material file can map its textures by triplanar projection instead of the model's UVs:
\"projection\": { \"mode\": \"triplanar\", \"space\": \"world\", \"scaleM\": 2, \"sharpness\": 4 }. This is for models whose UVs are missing or collapsed, such as modular building kits, which drew tiled textures as one flat colour. World space keeps adjacent pieces continuous; object space moves the texture with the object. Normal maps follow each projection. HD only for now; the standard renderer still reads the UVs."} - {"area":"engine","text":"A material file can take
\"variation\": { \"value\", \"hue\" }(each 0..1): every instance of the material gets its own shade, darker by up tovalueand shifted towards its own hue by up tohue(never brighter). The draw is a hash of the entity's scene id (and aninstancedMeshinstance's stable id), so a scene draws the same shades on every load whatever the order. Applied to the instance colour on the CPU: every renderer draws it, no shader cost, and a file without it draws exactly as before."} - {"area":"engine","text":"A mesh can override just some of a model's materials: \"materials\" on a mesh or instancedMesh maps a glTF material name to a material asset, so a car can have new paint and keep its glass. It wins over \"material\" for the names it lists; a name the model lacks logs mesh-material-name-unknown with the names it has."}
- {"area":"engine","text":"
argus minimap-bake <scene>draws a scene's roads from above into a PNG for a HUD minimap (ui/images/minimap.pngby default) and writes the ground area it shows beside it (minimap.json:minX,minZ,maxX,maxZ,width,height). The same scene and size give the same bytes. Options:--out,--size,--padding,--color(docs/UI.md, \"A track image for a minimap\")."} - {"area":"engine","text":"A look preset
natural-plus(meta.render.look.preset): natural with a blue-shadow and warm-highlight split, mild contrast (1.05), saturation 1.08 and a light vignette (0.12), no grain and no fog. Opt-in; scenes without it, and the default look, are unchanged."} - {"area":"engine","text":"meta.nav.live now follows a static collider a behaviour moves (a sliding door, a raised bridge), not only one it spawns or despawns. One that moves on every tick is rebuilt at most once every 6 ticks, and a live level is built as tiles so a mover rebuilds only the tiles it touches: no stall on the install tick."}
- {"area":"engine","text":"meta.nav.live: true makes the navmesh follow static colliders that behaviours spawn or despawn while the game runs (a door that closes, a bridge that is built). The tiles they touch are rebuilt off the loop and the new mesh is in place exactly 6 ticks later on every run. Off by default; existing scenes are unchanged."}
- {"area":"engine","text":"A snapshot taken inside a meta.nav.live rebuild's window carries the pending rebuild (optional
nav_livefield: install tick, gather tick, and the static changes since the mesh in force, by entity id), so a restore installs the same meshes on the same ticks as the original run. Snapshots without it, or over 64 changes / 64 KB, restore as before (docs/API.md)."} - {"area":"engine","text":"Prefabs can now contain other prefabs. A scene that places a car made of wheel prefabs loads and runs, with overrides at every level, the outermost one winning."}
- {"area":"engine","text":"HostConfig::networked() is the one setup a networked session runs (calls counted, a call depth limit of 256, no promise jobs, no SharedArrayBuffer), with a digest peers compare in the handshake; with_web_peers() also limits native peers to what the browser serves."}
- {"area":"engine","text":"NPC rules can drive separate action slots (move, aim, upper body, voice) with priorities and cooldowns, hand movement to a controller for racing, flocking or crowds, and script boss fights as phases with telegraph, attack and recover steps."}
- {"area":"engine","text":"NPC types can declare factions with relations and reputation, shared (faction and world) facts, a group decider that gives its members orders, a day schedule driven by a world clock, and events (damaged, talked, witnessed) that scripts raise with npc.damaged, npc.talk and npc.witnessed."}
- {"area":"engine","text":"NPC types can remember where they last saw or heard something, keep a list of several seen entities, tell kinds of noises apart (footstep, gunshot, alarm, damage), and shape awareness by angle. Scripts can raise a noise for NPCs with npc.stimulus, and npc.noise now says its kind."}
- {"area":"engine","text":"NPC types can ask position queries: cover from a threat, flank, flee, ambush, and search spots around any point such as the last place a target was seen. A query generates candidate points, filters them (reachable, hidden from the target, in range, unreserved), scores them and answers with the best. Answers are batched deterministically under a count budget and spots can be reserved so a squad spreads out."}
- {"area":"engine","text":"Snapshots now hold the NPCs: a restore (a rollback, a save loaded back,
POST /snapshot) puts every NPC type's simulation back exactly, with their decisions, facts, reserved spots, memory and decision logs, and what scripts had asked of them for the next tick, so the restored world plays on exactly as the original would have. The snapshot also says what each NPC is doing, for reading. Older snapshots still load; their NPCs start over as on a fresh load."} - {"area":"engine","text":"NPC starter packs: platformer enemy, patrol guard, stealth guard, racer, flock, squad soldier and schedule villager, each one generic TypeScript file in the gameplay npc packs folder with a scenario test, a replay-equality test and a golden hash list; docs/NPC.md lists them and notes that targetDist aims at the chest and that a rule timing itself with ticksSince also tests me.doing."}
- {"area":"engine","text":"A project can opt into Experimental features with an
experimentallist in its project file, for example[\"water/waterfall\"]. An export now lists the Beta and Experimental features the game uses, and says which Experimental ones are off because the project has not opted in."} - {"area":"engine","text":"The engine now keeps one feature list where every package (Foliage, Water, Exporter and the rest) is labelled Stable, Beta or Experimental, with the evidence for each label. Tests enforce the rules: Experimental parts are never on by default, and a package is never labelled above its lowest default-on part."}
- {"area":"engine","text":"Projects can now be upgraded to a new engine version in place:
project migrate --applyupgrades a project after backing up every file it changes, andproject migrate --restoreputs the backup back. Opening a project from an older engine now says which command upgrades it."} - {"area":"engine","text":"
argus run --record(and an--outshot) takes--aspect W:H: the frame is drawn natively at that shape (--viewport 1920x1080 --aspect 9:16is 1080x1920), keeping the viewport's longer side, rounded to even pixels.--shot-fov-fit vertical|horizontal|coversays how the camera's field of view meets it:verticalas authored (the default),horizontalkeeps the 16:9 reference view's width,coverkeeps the whole reference view in frame (for orthographic lenses too, and per cell in a split screen).record.jsonsaysaspectandfovFitwhen they were given."} - {"area":"engine","text":"
argus run --recordwritesaudio.wavbeside the frames: the game's sound mixed offline in step with the simulation, as long as the clip and the same on every run (reverb is left out, andrecord.jsonsays when)."} - {"area":"engine","text":"
argus run --no-huddraws recordings and screenshots without the game's UI and world labels, for clean footage (refused with--window,--serveor a managed session, and--headless); the game plays the same, andrecord.jsonsays\"hud\": false."} - {"area":"engine","text":"A recording's record.json now says which engine made it, which scene it was in (and from which frame, if the scene changed), and which files the scene uses with the licence each states."}
- {"area":"engine","text":"
argus run --recordtakes--supersample N(frames drawn at N times the size and filtered down, the HUD and labels kept at their size) and--warmup-frames N(frames drawn and dropped before the first, so HD's temporal effects settle).record.jsonrecords both. World labels now scale with a high-DPI window's device ratio, as the UI does."} - {"area":"engine","text":"A networked session can set HostConfig::refuse_async to refuse scripts that use promises, async or await, whose continuations run at a different point in the browser than natively; ctx.time.after and events do the same work deterministically."}
- {"area":"engine","text":"A replay now records a scene file reload made while it records (
argus run --watch, including an edit to a prefab file orargus.project.jsonthe scene takes, and the window's F5), as areloadlive edit, so the playback reloads on the same tick and plays the session as it ran. A replay without reloads is written exactly as before; an older engine refuses a file with areloadline instead of playing it wrong."} - {"area":"engine","text":"An animator's retarget map can list clip assets on the canonical humanoid (retarget.clips), such as the clip converter's output, and play them by name on a character with its own skeleton. A state naming a clip nobody has is now logged instead of silently holding the rest pose. (API since 0.7.0)"}
- {"area":"engine","text":"A built-in
road-driverbehaviour drives a vehicle along a road, which makes a rival kart a copy of your kart with\"input\": \"script\"and{ \"type\": \"script\", \"module\": \"road-driver\", \"props\": { \"road\": \"track\" } }. It steers along the road, slows for bends and backs out when it gets pinned against a wall. If it is still stuck after three tries, it sends astuckevent so your game can reset it.startOnandstopOnhold it still for a countdown and after the finish. It slows for tight bends and shortens its view ahead in an S, so it no longer cuts across the inside. A script can readctx.vehicle.minTurnRadius, the tightest circle the vehicle can turn at its current speed."} - {"area":"engine","text":"Road files can darken the road beside the kerbs (surface.finish.edgeWear) and give a raised kerb's outer face a shadow line (kerb.sideShade), at no extra geometry. Roads that do not set them look exactly as before."}
- {"area":"engine","text":"A road finish preset,
asphalt-neutral: neutral grey asphalt with fine grain and no glare (grain 0.2, wear 0, roughness 0.95, specular 0.25). It draws the road's default colour as a neutral grey; a colour the file writes wins. Files using the other presets are unchanged."} - {"area":"engine","text":"Three road finish presets with their own built-in pattern and colour, no texture asset:
plank(boards across the road with dark seams, weathered brown),cobble(staggered setts with dark joints, warm grey) andgravel(loose coarse and fine stones, dusty tan). A colour the file writes wins over the preset's. Roads using asphalt, worn-asphalt or concrete are unchanged."} - {"area":"engine","text":"Road files can paint lane markings (markings.edge lines and a solid or dashed markings.centre line, built into the road so they never flicker against it) and choose a kerb style (kerb.style ramp, block or flat). Both are optional: existing roads build exactly as before."}
- {"area":"engine","text":"Roads can draw a chequered start line:
markings.start {atS, rows, colors}puts an even number of squares about 0.5 m wide across the driving width,rowsdeep, fromatSmetres along the road. It is drawn only (the road's collider is unchanged), and a road file without it builds exactly as before."} - {"area":"engine","text":"Road files can give the road a built-in finish (surface.finish: asphalt, worn-asphalt or concrete, with grain, wear and roughness amounts): a matte surface with fine grain, soft patches and darker wheel tracks, made by the engine with no texture asset. Roads without it look exactly as before."}
- {"area":"engine","text":"The rock scatter tool (
flora-scatter-rocks) can place a rock mesh you already have: a terrainscatterop withasset: \"rock:glb/<scene-relative .glb>\"and a<name>.place.jsonbeside the glb (heightM,footprintRadiusM, and optionallysinkFrac,facing: \"slope\"for a cliff piece that faces out of the face it stands against,yawJitterDeg,embedM). The tool writes only the.instancesfile and points the scene at your glb. Scatter ops take a new optionalsinkFrac(0 to 0.9), the share of a mesh's height buried, which overrides the sidecar's. Every instance is settled so no point of its footprint floats over the ground. Ops without these fields place exactly as before. A piece is never buried deeper than 0.9 of its height: where a rock that rests would have to sink further to stand on a steep slope without floating, it is not placed. Names with a:and links that leave the scene folder are refused, and asinkFracon an op that places no mesh is warned about.flora-scatter-rocks --keep-clear X,Z,R(repeatable) keeps every rock out of a circle, for a camera's eye or a hero spot."} - {"area":"engine","text":"An animator can take root motion from a named joint such as the hips (rootMotionFrom), for clip packs whose travel lives in the pelvis while the rig root stays at rest; a hint at load says when a root-motion state needs it."}
- {"area":"engine","text":"With animator rootMotionFrom set, a state without rootMotion plays in place: the named joint's ground travel is dropped from the pose and not reported, so locomotion whose speed a script owns stays over the capsule"}
- {"area":"engine","text":"The HD renderer can leave small instances (ferns, weeds, debris) out of ray tracing with the new rt_min_radius_m setting. Off by default."}
- {"area":"engine","text":"The foliage scene manifest's scatter layers accept height_m (a target height range in metres, measured against the template's tallest described height) and mature_bias (pushes ages toward the old end); both default to off and are pay-for-use, so existing manifests place exactly as before."}
- {"area":"engine","text":"Terrain
scatterops take an optionalroadKeepOffM: nothing the op places comes within that many metres of a road's bare edge (the strip ground cover also leaves bare), so trees stay off the run-off. Files without it place exactly what they did."} - {"area":"engine","text":"The foliage scene's valley run knows a
timberlinescatter mask: the terrain's forest channel while it fades (0.02 to 0.6), on ground of 12 to 50 degrees that is not snow, ice, river bed or water (scree and rock allowed), so a treeline band on a steep wall can take trees that the forest and treeline masks (38 and 45 degrees) refuse, and the flat valley floor takes none. Off unless a layer names it; existing manifests place as before."} - {"area":"engine","text":"Scenes can set a colour grade with meta.render.look: a look preset (natural, cinematic, bright-day, overcast, night, stylised) plus contrast, saturation, white balance, a black point and vignette. HD applies the full preset grade; the standard renderer applies contrast, saturation, white balance and the black point. Without it, frames are unchanged."}
- {"area":"engine","text":"A self-test report now carries
digest, a fingerprint of the game's state at the end of the run. Running the same scenario on two engine builds (the development engine and an exported game, two platforms or two releases) and comparing the digests shows whether they played the game the same way."} - {"area":"engine","text":"A self-test can now drive a car or kart round a track. The new step
{ \"drive\": \"road\", \"road\": \"track\", \"frames\": 1800 }holds the throttle and steers along the road every tick, as a driver would, and reports how far it got and how far it strayed off the road;minDistanceMmakes the step fail if it got less far than that."} - {"area":"engine","text":"The profiler now shows what a reader costs a running game: a
serve.publishspan for each publication of the world's state to the query API, andserve.publish.scriptsunder it for the walk of every behaviour'sctx.stateonce something has read an entity (docs/PROFILER.md, \"The query API\")."} - {"area":"engine","text":"Shaders can declare array texture slots (a list of layers per material, read with a layer index), up to two per-draw texture slots, and use exact texel loads, gradient sampling and the surface's world-space derivatives (worldDdx, worldDdy). Engine stock modules may use a larger parameter block and their own cost cap."}
- {"area":"engine","text":"A shared-screen co-op camera that splits: ctx.views.shared(targets, opts) frames every player in one view and, when they spread too far apart for it, splits the window into one view per player (two side by side or stacked, three, or a grid of four), merging back when they regroup. Separate split and merge distances and a short hold on game time keep it from flickering; each switch raises a views-split or views-merged event."}
- {"area":"engine","text":"Deterministic f32 maths (sin, cos, tan, asin, acos, atan, atan2, exp, ln, powf) for gameplay code, and a check that keeps platform maths and the wall clock out of the simulation."}
- {"area":"engine","text":"The nightly sim-hash run drives kart-starter, pebblewind-heights and hop-lane with synthetic input (
<root>|<scene>|input:<seed>: every action of the live input context, a pure function of seed, action and tick), so their controllers, vehicles and input scripts are hashed under input rather than idle. Unlike a recorded replay it needs no file and does not go stale at an engine version bump or a scene edit."} - {"area":"engine","text":"A sky can show a colour or gradient of its own behind the scene (sky.background) while it still lights the scene as before: a flat bright sky no longer tints everything it lights."}
- {"area":"engine","text":"GET /snapshot?solver=false answers the world without the physics solver's opaque state (no bit-exact restore, a fraction of the size); the playtester's softlock check reads it, which made a kart-track critic.play run (8 scripted karts, mesh-collider track) about 17% faster."}
- {"area":"engine","text":"Audio supports up to four listeners for local split screen. Each spatial sound is heard by the nearest listener, which sets its volume and stereo position, and an equal-distance tie goes to the earlier view. A sum-of-listeners mix is available as an option. With one listener the output is exactly what it was before (docs/AUDIO.md)."}
- {"area":"engine","text":"Split screen now gives every view its own audio listener at its camera, so each player hears the sounds near them from where they are. One view sounds exactly as before.
ctx.audio.listenFrom(\"camera\")keeps one listener on player 1's camera, andctx.audio.setListenerPolicy(\"nearest\" | \"sum\")picks how several listeners hear one sound (docs/AUDIO.md)."} - {"area":"engine","text":"Split screen for local multiplayer: ctx.views sets a layout of up to four views, each with its own camera, plus a camera that frames several players on one shared screen; and scene cameras with output \"viewport\" are now drawn into their rectangle. Behaviour change: a scene that already had an output \"viewport\" camera now draws that extra view (before, it validated and drew nothing)."}
- {"area":"engine","text":"Characters can have secondary motion: a
springBonescomponent swings chosen bones (hair, a tail, a cape) on springs after the animation, with stiffness, damping, gravity and sphere or capsule colliders on other bones. It runs at a fixed step, so the same scene always moves the same way. Attachments do not follow the springs yet."} - {"area":"engine","text":"Effect files can name an effect preset (
\"preset\": \"builtin:fx/puff-burst\"with param values) instead of spelling out every emitter, and sprites can draw a built-in hard-edged shape (disc, ring, star, blade, puff, flake) with a shade band and an ink rim instead of a texture. The first presets are dust, a puff burst and confetti. The standard renderer draws the shapes crisply at any size, without an image; HD still draws them as the soft disc for now."} - {"area":"engine","text":"The engine now warns (teleport-position-ignored) when a behaviour writes an entity's old position back over a teleport from a tool, the editor or a test harness, naming that behaviour, and the critic warns (behavior-position-ignores-teleport) about a behaviour that writes a position every tick from its own state without handling the teleported event."}
- {"area":"engine","text":"A terrain file with sculpt and paint ops loads its delta tiles from the .terrain folder beside it, and the engine can re-cook, re-collide and redraw just the cells an edit touched (World::terrain_refresh_cells), the groundwork for the editor's terrain sculpt and paint tools."}
- {"area":"engine","text":"Terrain layers can set
canopyM(crown spacing, metres): where the layer is painted and a crown spans under about 70 pixels, the material draws a field of rounded crowns (lit domes, dark gaps) instead of the texture, so forested slopes read as forest from afar (renderer only, HD and standard profile)."} - {"area":"engine","text":"A terrain can grow grass and forest floor in HD: give its terrain component a groundCover (a preset such as meadow-forest, or your own layers). The cover grows where the terrain's channels or layers say, fades softly at its edges, stays off rock, water and steep ground, and takes the colour of the ground under it, so it blends into the terrain. A cover layer reads every channel and layer its source names and grows where the densest of them is, so a narrow channel no longer hides the terrain layer of the same name. The built-in presets are natural alpine greens with gold-green tips."}
- {"area":"engine","text":"A material file can name an optional heightTexture (linear, R); terrain layers blend by it, falling back to the occlusion map or the colour's luminance as before."}
- {"area":"engine","text":"A terrain can now shadow itself past the sun's shadow distance (
horizon: trueon the terrain component, a new optional field of the scene contract; off by default, and scenes without it save byte-equal): a valley goes into shade when the sun drops behind the ridge, with no pop where the shadow maps end, and deep valleys get less light from the sky. Off with ray-traced shadows and GI, which already see the terrain."} - {"area":"engine","text":"A terrain file's surface block can set macroCavity (strength 0 to 1, optional scalesM): hollows and gullies draw darker and ridges lighter by the ground's curvature, at no per-pixel cost. Absent, the terrain looks as before."}
- {"area":"engine","text":"A terrain file's surface block can set macroDetail (strength 0 to 1, optional wavelengthM): rock on steep ground keeps mottled value, yellow lichen and green moss patches, a warm lift on crests and shallow ribs at tens of metres after its layer textures fade to their mean colour, so far rock is no longer flat; meadow, forest and snow are left alone. Absent, the terrain looks as before."}
- {"area":"engine","text":"The alpine valley's mountains now have sharp ridges, spires, layered cliff bands and scree skirts instead of smooth rounded ridges: a new
ridgedMultinoise (ridged multifractal with a domain warp), uneven wobbling strata interrace(stepVar,wobbleM) and lumpy talus slopes inerode.thermal(talusNoise); the rivers and lakes are exactly as before."} - {"area":"engine","text":"
material.rulesrules takesoftEdge: true: the rule'sfallofframp now blends its layer into the ground it lies on (before, a layer was painted in full wherever its ramp was above zero, so material patches read as hard-edged decals),noiseMripples the ramp itself rather than speckling the whole patch, and the second layer fades out before a third replaces it. Absent or false: unchanged."} - {"area":"engine","text":"Terrain looks better up close and far away: rock follows real cliffs and snow lies by altitude with soft, ragged edges (a new optional surface block in the terrain file), steep banks no longer stretch their texture, tiles no longer visibly repeat, ground beside rivers and lakes is darker and wetter, layers keep sharper textures (up to 1024 texels) and use their roughness maps."}
- {"area":"engine","text":"Terrain surface.rockBeds can take strataFrom, an erode.thermal op id: the tint bands (and streaks) then sit on that op's beds, hard where its hardness is 0.9 or more, and follow its strataTiltM tilt, instead of the hashed beds of bedM. HD only; the band table rides in three extra material-table slots of a terrain that sets it, and a terrain without it draws and saves exactly as before."}
- {"area":"engine","text":"Rock can be tinted bed by bed, with water streaks: a new optional
surface.rockBedsblock names a rock layer and tints its beds (hard beds pale and cool, soft beds warm and dark, one bed in N rust, a seeded jitter and a roughness difference per bed) and draws dark streaks below each bed's lip (weaker in hollows, by the mesh's cavity), in HD's raster and, as tint only, in ray-traced hits (reflections, GI bounces). The beds are the rock detail's (same noise and hash), so a tinted bed ends where its ledge does; it uses no extra layer slot. The bed geometry is deterministic across machines; the shader's tint matches the CPU's except for sub-pixel slivers at bed boundaries (WGSL fused multiply-add and division). HD only; absent, terrains draw and save byte for byte as before.rockBeds.crackDarken(default 0.6 with the block) also makes the rock detail's recesses darken; withoutrockBedsthey do not. The ray-traced hits' tint turns off again when the last terrain with beds unloads."} - {"area":"engine","text":"Terrain rockDetail can cut ledges and blocks into HD cliffs: benchM, benchDutyPct and benchEdge make hard beds jut out with a sharp riser and a flat tread, jointSpacingM, jointDepthM and jointAzimuthDeg cut two square sets of vertical joints into stacked blocks, dipDeg and dipAzimuthDeg tilt the beds (they descend toward the azimuth), and strataFrom takes the bed heights and hardness from an erode.thermal op's strata. All optional; a file without them draws exactly as before. strataFrom keeps up to 64 bands and follows that op's strataTiltM tilt, so the benches stay on its shelves."}
- {"area":"engine","text":"Terrain can carry rock detail in HD: steep faces are refined and displaced into strata, chips and runnels within a triangle budget (surface rockDetail). Procedural boulders and outcrops can be scattered over a terrain by its own scatter rules and drawn as instanced meshes (flora-scatter-rocks)."}
- {"area":"engine","text":"A new terrain op,
erode.talus, gives cliffs talus aprons: ground steeper thansourceDegsheds up toweatherMof rock as debris that comes to rest at the angle of repose below it, in fans and cones, and writes the debris depth to thescreechannel. Height is conserved exactly atbulking1, and a recipe without the op is byte-identical."} - {"area":"engine","text":"
erode.thermaltakesstrataTiltM(0 to 1000 m): its strata bands follow a world-position noise of that amplitude (wavelengthtalusNoiseM, default 240 m), so the beds tilt and undulate instead of standing at the same heights on every face. Absent or 0: unchanged."} - {"area":"engine","text":"Terrain volume rock now collides and the terrain ground query reads it: a body lands on an arch's top or on the ground under it, a capsule walks through, rays and the new
surfaces(x, z)andground_below(x, y, z)see every surface of a column, wheels take the friction of the surface they are on, and nav builds paths under arches and overhangs from the rock's collision mesh (argus_nav::terrain::volume_geometry). The game engine takes this behind theterrain-volumefeature, off by default until the rock is drawn. Terrains without volume ops are unchanged."} - {"area":"engine","text":"Terrain volume rock (arches, overhangs, pinnacles, tunnels, cliffs) is now drawn in both renderers: every terrain LOD takes in its cell's rock at a matching level (a chain of doubling voxels), closed against the ground with no seams or sky gaps; the rock carries a cavity term baked from its field (shade under an arch, open on top) and draws in its op's own layer (for example
rockon an arch's gentle top, not the grass of the layer map under it). Rock detail no longer moves the rim of the ground opened under the rock. Behind the game engine'sterrain-volumefeature; terrains without volume ops draw exactly as before."} - {"area":"engine","text":"Two new terrain ops build 3D rock on the heightfield:
volume.shape(arches, overhangs, pinnacles, boulders and tunnels from boxes, fractured polytopes, swept slabs, tubes and ellipsoids) andvolume.cliff(bedded, jointed rock walls with overhanging hard beds on steep ground). They come last in the stack, with two new rule codes,terrain-volume-invalidandterrain-volume-order; a file without them is unchanged. The rock is not drawn or collided yet: until it is, the editor and the game refuse a file that uses these ops, naming the op."} - {"area":"engine","text":"An atmosphere sky's preset is now a time of day: golden-hour, overcast, dusk and night set the sun, clouds, haze and a fog together, and anything the scene writes still wins."}
- {"area":"engine","text":"A
font-familythat names no font the game loaded now says so, once per family:render.text.unknown-familynames the family, lists the fonts that are loaded, and says which one the text draws in instead. Before, the text quietly drew in another font (a whole game's UI in the wrong face, with nothing in the log)."} - {"area":"engine","text":"Ordinal strings in
ui/locales/<tag>.json: a message written{ \"ordinal\": { \"one\": \"{n}st\", \"two\": \"{n}nd\", \"few\": \"{n}rd\", \"other\": \"{n}th\" } }picks its form fromnby the language's CLDR ordinal rule (English, French, Italian and Swedish have more than one form; every other language has one), so a race position reads 1st, 2nd, 3rd, 11th, 22nd. Existing locale files read exactly as before (docs/UI.md, \"Ordinals: 1st, 2nd, 3rd\")."} - {"area":"engine","text":"Game UI can animate from the stylesheet:
animation: <preset> [duration] [delay] [infinite]plays one of eleven engine presets (pop, slam-in, slide-in-up/-down/-left/-right, fade-in, pulse, bob, shake, stamp) when its rule starts to match, at paint time only (no layout), on the UI frame clock, and skipped under reduced motion. A stylesheet withoutanimationdraws exactly as before."} - {"area":"engine","text":"Forests can scatter ready-made models (ferns, weeds, fallen logs and stumps) as undergrowth from a pieces index: they tilt to the ground, logs lie across the slope, stumps sit partly buried, ferns and weeds stand in patches of 3 to 10 that thin out with distance, and a scene draws from one texture set per shape group (at most five sets, 64 MB of textures and twelve distinct models by default; ground cover such as grass and moss, and saplings, are left out, and heavier models are passed over when lighter ones exist). Undergrowth stands around every camera of a scene (and any extra point given with --near), and a model that breaks a size limit is skipped with a warning instead of rejecting the whole index. Models that decode to more than 32 MB (file plus textures) are skipped, so a scene never overruns the engine's asset cache; the 1k texture copies pass."}
- {"area":"engine","text":"Vehicles can float and drive on water: a new
waterblock on thevehiclecomponent adds thrusters (propellers, or jets that steer with the throttle), a rudder, a keel, planing lift and an optional righting torque, on a body withbuoyancy. A boat or jet ski needs no wheels; a car or kart with wheels becomes amphibious, handing over between its wheels and the water as it drives in and out."} - {"area":"engine","text":"Particle effects can collide: a new collide module makes particles bounce, stick or die on the terrain and the water (and, on the GPU, the depth buffer). It is behind the vfx-collide build feature, which is off by default."}
- {"area":"engine","text":"Particle effects can leave a decal where a particle hit a surface or died: an
eventsentry with adecal(texture, size, life, fade-out and a per-effect cap), shown on the HD renderer about two frames after the hit; the standard renderer and headless runs make none."} - {"area":"engine","text":"Particle effects: a *.vfx.json asset describes up to eight emitters with spawn rules, shapes, curves, gradients, forces, wind and parameters. A particles component can use one with
effectandparams, and scripts can start one (ctx.particles.play), set a parameter or fire a burst. The built-in presets keep their look and are available as builtin:smoke and the rest. The engine binary grows by about 241 KB (+0.8%, stripped release) for the effects system. (API since 0.6.1)"} - {"area":"engine","text":"Particle effects can start particles in a child emitter when a particle dies or collides (
eventsandrole: \"child\"in*.vfx.json), with a count per particle and a share of the parent's velocity; the same on the CPU and the GPU, and runs repeat byte for byte."} - {"area":"engine","text":"Particle effects draw on the HD renderer with flipbook sheets (with frame blending), velocity-aligned streaks, flat and custom facing, premultiplied blending, lit or emissive sprites and a per-effect soft fade, all simulated on the GPU. (API since 0.6.1)"}
- {"area":"engine","text":"An effect that names a preset can now cap its on-screen size and adjust its sprite (softness, glow, texture) without copying the whole preset."}
- {"area":"engine","text":"Particle effects can draw trails: an emitter with a ribbon renderer joins its live particles into one strip that tapers and fades along its length, on both the HD and the standard renderer."}
- {"area":"engine","text":"
argus-visemescan be built withlipsync-onlineto ask a service you configure, with your own key in a file only you can read, for a lip-sync track (--online <name>). It is off in every default build, and this version reaches only a service on the same machine."} - {"area":"engine","text":"
argus-visemescan make a lip-sync track with Rhubarb Lip Sync from the line's audio (--from rhubarb), as well as from its text, and keeps tracks in a cache keyed by their input (--cache). A track now says which tool made it in an optionalsourceblock, which the engine ignores."} - {"area":"engine","text":"Lock-on camera rig (
ctx.camera.set(\"lock\", {target, ...})), script-driven controllers step after the behaviours soctx.controller.move/jump/setVelocityland on the tick they are asked, and theanimator-window-unreachableruntime warning."} - {"area":"engine","text":"Feel probes: camera.turnLagDeg is measured without a lock target (the camera's heading against the player's body yaw while it turns (velocity heading when no yaw), so a chase camera behind a vehicle reads); a platformer-2d profile (sourced rows only) is auto-picked for a side-on jumper; a jump buffer or coyote time of 0 is worded as absent, with the feel reason, in movement.details. The kart-racer camera.turnLagDeg band is dropped (no source)."}
- {"area":"engine","text":"Boats, jet skis and anything floating now leave wakes and foam trails in the water, throw spray off the bow at speed, and splash when they drop in. HD draws the wakes on the sea, lakes and rivers; the standard renderer shows the spray and simple foam puffs."}
- {"area":"engine","text":"In the browser, ctx.animator's play, set, state, speed, param, window and lookAt now work as they do natively, with the same errors, so duel-yard runs in the browser with no script errors."}
- {"area":"engine","text":"A game exported for the web now makes sound: the same mixer and voices as on the desktop reach the browser's WebAudio. The sound starts with the player's first click, key or touch on the page, as browsers require."}
- {"area":"engine","text":"A web export bakes the navmesh of every scene that uses navigation (argus nav-bake), so navagents walk in the browser too."}
- {"area":"engine","text":"A web export can also be a zip ready to upload (--zip, index.html at its root) with precompressed files beside it (--precompress), carries a hosting README, reports its size budgets, and has a --json mode the editor and agents read."}
- {"area":"engine","text":"The web runtime serves
ctx.body,ctx.vehicleand a vehicle's wheels: pushes and impulses, setting a body's velocity, reading its motion, mass and wheels, driving a vehicle and reading its state, and a wheel's torque, steer and contact. A browser game gets the same answers and the same errors as the desktop engine. With particles (coming separately), the kart starter runs in the browser."} - {"area":"engine","text":"A scene can ship its navmesh baked beside it (<scene>.navbake, written by World::bake_navmesh): the web build, which cannot build a navmesh, loads it, so navagents walk in the browser; a native build uses it too, so both walk the same polygons."}
- {"area":"engine","text":"In the browser, ctx.views, ctx.players (list, count, of, leave), ctx.data.record, ctx.particles (emit, play, setParam, burst), ctx.world.raycast and setSensor, ctx.camera.shake and ctx.input.rumble and setContext now work as they do natively, with the same particle scatter keys, so twin-trail needs nothing more from the web host (duel-yard still needs three ctx.animator members). A wrong argument now throws the same error in the browser as on the desktop, and a call that returns nothing gives undefined there too, not null."}
- {"area":"engine","text":"An installed engine can carry the browser runtime, so
engine export --target webworks without a source checkout; a runtime built for another engine version is refused with a clear message."} - {"area":"engine","text":"In the browser, ctx.entity.set and ctx.controller.setVelocity / addVelocity now work as they do natively, with the same refusals."}
- {"area":"engine","text":"In the browser, ctx.sprite (every member), ctx.entity.visible, the rest of ctx.controller and ctx.camera.viewSize now work as they do natively; lantern-hollow and hop-lane run in the browser with no script errors."}
- {"area":"engine","text":"In the browser, ctx.entity.teleport and ctx.audio.play now work as they do natively (same answers and voice numbers); the sound itself does not play in the browser yet."}
- {"area":"agent","text":"An agent's asset.import now imports FBX models too: the file is converted to a GLB (metres, Y-up) by your own headless Blender, exactly as the editor's Import model... does, and the asset records the FBX's name and SHA-256. With no Blender the refusal names the ARGUS_BLENDER variable and nothing is written."}
- {"area":"agent","text":"Agents with the library toolset can run a provider's Smart UV, humanoid auto-rig or retopology step on a model in the project with library.process, on the user's own key, after the same opt-in, approval and spend checks as generating. A dry run shows the price first."}
- {"area":"agent","text":"Agents can put a named look on a scene in one call:
look.apply {look: \"sunny-midday\"}(toolsetview) replaces the scene's sky, ambient light and render look with the look's, as onescene.patch(one undo), and touches nothing else. It answers what those blocks were. An unknown look is refused with the list of looks. Each look is alook-<name>recipe, so adding a look needs no code."} - {"area":"agent","text":"Agents can edit a road file:
road.edit(toolsetmeasure) sets or removes fields of a.road.jsonby dotted path, such asmarkings.startfor the chequered start/finish line orsurface.finish.preset, through the road entity or the file's path. The edited file must pass the road parser and build, or the call is refused with the parser's own message and nothing is written. Each edit is one change thatreverttakes back byte for byte, and the file keeps its key order."} - {"area":"agent","text":"Agents can run the game's self-test scenarios (selftest/*.json, or one passed inline) with critic.selftest in the new selftest toolset, which answers pass or fail per step with the failing step, the reason and the values read; critic.play now warns play/untested-flows on a goal-less game with no scenarios."}
- {"area":"agent","text":"Importing a model with morph targets (blend shapes) records their channel names on the asset entry as morphs, and the import answer lists them."}
- {"area":"agent","text":"A new opt-in agent toolset, buildings, builds houses, town walls, bridges, whole street frontages and walled town layouts from parameters (footprint, floors, style, roof) out of a kit of modular pieces, standing them on terrain, as one undoable change that regenerates in place."}
- {"area":"agent","text":"building.generate takes dormers (a share from 0 to 1): that share of a pitched roof's lowest slope cells, away from the roof's ends, becomes the kit's dormer pieces."}
- {"area":"agent","text":"Concept images can be asked for on a grey, black or transparent backdrop instead of always white (
backdroponconcept; white stays the default): grey suits faces and pale subjects, black bright ones. The concept keeps its backdrop for its other views and every edit round, the drafts' checks accept any plain colour, and image-to-3D keys any plain backdrop out. Agents can now also pass a concept's draft count, views per draft and budget (n,views,maxUsd) throughlibrary.share; the tool refused them before."} - {"area":"agent","text":"Concept images can be drawn from a picture you give (
referenceonconcept: a PNG in the project folder, up to 20 MB; links and files outside the project are refused, since the picture goes to the image service), so a design stays the same across concepts: each first view is an edit of your picture, framed and styled like a drawn one. The concept keeps the picture and sends it along on its other views and every edit round, and reuse offers only a concept made from the same picture. Agents can pass it throughlibrary.share."} - {"area":"agent","text":"Claude Code running inside WSL can now use the Talos tools: argus-hub --connect-ai <project> --client wsl writes a command WSL can start (the launcher's /mnt/c/... path). Add --approve to also approve the server in the project's .claude/settings.local.json. A project inside the Linux file system or at a \\\\wsl.localhost path is refused with an explanation."}
- {"area":"agent","text":"The engine now ships a building kit of its own (Kenney Fantasy Town, CC0): ask your AI for a house, a village or a town and it calls building.kit with no folder, then builds from it, and can line the streets with its trees, lanterns and market stalls. No models to download first."}
- {"area":"agent","text":"Generated houses now get a step under each front door when the kit has step pieces, and building.generate takes doorHood (canopy or porch) to put the kit's hood or porch over each ground-floor door."}
- {"area":"agent","text":"dress rules take doorClearM (a rule's objects keep out of a 2 m strip that far out from every generated building's ground-floor doors) and maxHeight (only pieces at most that tall, at the rule's largest scale)."}
- {"area":"agent","text":"critic.play feel gains two probes, actions and impact: each button of the gameplay context is pressed once and read every tick for startup, active, recovery and total, whether the cancel window can be reached, and an attacker's wind-up against a person's reaction; each impact (a sensor overlap or a hit, damage, impact or hurt event) is read for hit-stop, push, camera shake, sound, particles, rumble and HUD change within 300 ms; the camera probe also frames the focus target, and the verdict's feel.metrics carries every number by id"}
- {"area":"agent","text":"Feel probes: the run action's foot slide is reported as movement.footSlideMs[run] (or [sprint]) and judged by the same profile row, movement.turn180RateDegS is a registered metric beside the 90 degree turn rate, and the actions probe warns (feel/action-out-of-reach) when a swing's hit volume never gets within reach of the nearest target, saying how far it ends from it."}
- {"area":"agent","text":"The feel probes are now checked live on a real legged rig (the CC0 Quaternius mannequin, feet named in animator.feet): the walk and run foot slide is measured, and a punch that lands raises no out-of-reach warning while one aimed at a far post does."}
- {"area":"agent","text":"parcels.subdivide fit.facade takes balconies and outsideStairs (shares 0 to 1): that share of the main buildings, rows included, gets one balcony on the door's side at a seeded upper storey, or an outside stair on a free side (never a party side or the door's), where the kit has the balcony-rail or stair and stair-landing pieces; absent or 0 builds as before."}
- {"area":"agent","text":"parcels.subdivide takes fit.facade {doorHoods, shopfronts, dormers}: that share of the buildings, rows included, gets door hoods (half canopies, half porches) and shopfronts, and every roof gets the dormer share."}
- {"area":"agent","text":"
foliage.preset {scene, preset, area, seed?, dryRun?}(foliage toolset) andargus-agent foliage-preset: plant a scene's terrain over an area with a foliage preset in one call. It writes existinginstancedMeshentities (taggedfoliage-preset:<name>, under onefoliageentity) with their.instancesfiles and models in the scene'sassets/foliage-preset/, and answers instances, models and full-detail triangles against the preset's budget. A re-run replaces the preset's planting; the same call gives the same bytes; revert takes it back, models it created included. Disk-mode journal entries now keep binary files and removals."} - {"area":"agent","text":"building.generate takes paving (a depth up to one cell), and fit.facade a paving share: the kit's paving tiles outside each side with a door, as deep as the room to the plot's street front allows (none under 0.6 m), so row houses' strips meet into a pavement."}
- {"area":"agent","text":"On a machine with no display, editor.start now starts the project's workspace service alone, and play.start, play.step, play.input, play.query and play.capture run in a headless engine, so an AI on a headless Linux box can build and play a game through the agent."}
- {"area":"agent","text":"Building kits may now carry pieces for door canopies, porches, shopfronts, door steps, lean-to roofs, roof valleys and street paving (new piece roles). Kits without them build exactly as before; placing them comes next."}
- {"area":"agent","text":"A small read-only demo asset library in the repository (
assets/library-demo/, one CC0 crate made by the modelling guide's example script) lets you try shared search and fetch offline with nothing set up;packages/assets/scripts/build-library-demo.tsrebuilds it (and a larger set) locally. A library folder that holds only its public key is now read-only: publish and retire are refused instead of replacing its key, and a fetch writes nothing into it. The asset gate no longer rejects a model whose first level of detail already shrinks past the second level's target; that level is simply not made (the guide's own example crate was rejected)."} - {"area":"agent","text":"The shared asset library can take a model from outside the company: it checks the file with the quality gate, measures it, publishes it under the maker's own signed rights statement, and can take any asset down from every partition if it turns out not to be theirs to share. The intake reads files only from the runner's download folder (set
ARGUS_INTAKE_DIRto it; anything outside it, or any file that is missing, unreadable, oversize or not a model, gets one identical refusal), takes a modelling script as text, measures the size from the file, keeps the company's own names and machine handles for itself, counts each key's limits across processes, and signs the credit line, description and facets into the maker's attestation (version 6). A takedown records a short code in the public snapshot and keeps its free-text note (at most 500 characters, no personal data) inside the company only."} - {"area":"agent","text":"The shared asset library now requires metadata on every asset, measured from the file itself (triangles, size, textures, colours, materials), and shows star ratings and download counts. Search can filter and sort on all of it and says why each asset matched, and each asset keeps its untouched original next to an optimized copy for each quality profile."}
- {"area":"agent","text":"The shared asset library can be seeded from CC0 asset packs, keeps a lossless original of every converted piece, and now offers web and mobile copies of each model next to the standard one, so a search for a lighter profile finds assets that fit its budget. Machines that only read the library need just its public key."}
- {"area":"agent","text":"The shared asset library can now live in two S3-compatible cloud buckets (internal and public) as well as a local folder, and several machines can publish to it at once without overwriting each other. Assets keep their untouched original file next to the game-ready copy, and assets made with a paid generation-service plan that the sharing policy allows can now be published for all engine users."}
- {"area":"agent","text":"A new recipe, melee-moveset, shows a three-hit combo gated by animation cancel windows, a blade that hits only during each attack's hit window, a dodge roll moved by root motion, and an upper-body swing while running."}
- {"area":"agent","text":"Provider API keys can also come from a key file you create yourself, one per provider in your keys folder (for Mureka: keys/mureka.key in your user config folder). It is read only when only you can read it, and clearing a key never deletes it."}
- {"area":"agent","text":"A town can now grow around a race track. Give network.grow the track as a fixed street (
fixed: [{road: \"track\"}]) and the town's main street follows the track's own curve, keeps its houses clear of the kerbs and barriers, and draws no second road over it."} - {"area":"agent","text":"network.grow's classes take kerb, finish and markings: each road of the class gets that kerb, surface finish (for example worn asphalt with edge wear) and markings, checked against the road format up front."}
- {"area":"agent","text":"The playtester now plays games driven by the mouse: for each action bound to a mouse button it puts the pointer on every thing in view, and on a grid of points, then clicks, and reports which clicks changed the game. It needs an engine that takes a pointer and can project a world point to the screen; without them it says so and clicks in place or on the grid."}
- {"area":"agent","text":"The playtester now walks a game's menus when there is no one to play and a screen keeps the input: it presses every button on every screen once (never Quit or Delete) and reports buttons that do nothing and screens with no way out. A settings toggle that only saves a choice or plays a sound counts as doing something. The critic.play tool takes a kind argument to pick the driver."}
- {"area":"agent","text":"The agent's buildings toolset now grows street networks over terrain between points of interest (roads that carve the ground, switchbacks on hills), splits the blocks into plots and fits kit buildings to them, and places props by rule along streets, in plazas and in yards; each call is one undoable change that regenerates in place.
network.growandparcels.subdividereplace the retiredtown.frontageandlayout.generatetools."} - {"area":"agent","text":"Rows of joined houses can now turn every second house's gable to the street (fit.rows.gables) and step every second run of houses back 1 to 2 m from the street (fit.rows.stagger), so a street reads as separate houses rather than one long block. Both are off unless you ask for them; Details lists them. A house only turns its gable to the street where its roof and its neighbours' roofs clear each other, so roofs never cross."}
- {"area":"agent","text":"Rows of joined houses can now jetty their upper storeys out over the street: fit.rows.jetties (0 to 1), where the kit has jetty walls. A jettied house's roof now follows its upper storey on kits that build roofs from small pieces, and a jettied house's shared wall with a neighbour no longer gets windows. Off unless you ask for it."}
- {"area":"agent","text":"Rows of joined houses can now vary their roofs: fit.rows.roofs (0 to 1) lets a house that stands above its neighbours turn its gable to the street and one below them take a hip roof. building.generate takes ridge (x or z) to choose which way a pitched roof's ridge runs. Both are off unless you ask for them."}
- {"area":"agent","text":"Rows of joined houses can now draw their storey counts from a range you give (fit.rows.storeys, such as [1, 3]) instead of the house type's, so one-, two- and three-storey houses can stand side by side. Off unless you ask for it."}
- {"area":"agent","text":"Rows of joined houses (parcels.subdivide fit.rows) can now vary their massing: fit.rows.variety (0 to 1) makes neighbouring houses differ in storeys more often and sets some runs of houses back from the street by up to 0.6 m, so a terrace no longer reads as one long block. It is off unless you ask for it."}
- {"area":"agent","text":"Rows with front yards can now have front wings: fit.rows.wings (0 to 1) gives some taller houses a one-storey wing in front of the door, its gable to the street, so the frontage steps in and out. It is off unless you ask for it; Details lists it for a selected town."}
- {"area":"agent","text":"Rows of joined houses can now have front yards: fit.rows.yards (0 to 1) sets runs of one to three houses back 1.5 to 3 m behind a fence along the street, with a gate opposite each front door, where the plots have room. It is off unless you ask for it; Details lists it for a selected town."}
- {"area":"agent","text":"building.generate takes shopfront (bool): the ground floor of each side with a door, apart from the doors, uses the kit's shopfront pieces."}
- {"area":"agent","text":"Houses can now have taller or lower storeys than their kit's: building.generate takes storeyScale (0.5 to 2; the house is stretched in height, so doors and windows get taller too), and rows of joined houses take fit.rows.heights (0 to 1), which gives runs of houses a different storey height from their neighbours so the eave line steps along a street. Both are off unless you ask for them; Details lists them."}
- {"area":"agent","text":"The agent can build and see terrain rock a heightfield cannot hold.
terrain.opslistsvolume.shape(arches, overhangs, pinnacles, tunnels) andvolume.cliff(bedded cliffs that overhang) with a worked example each.terrain.previewgains two side views:section:x0,z0,x1,z1(a vertical cut that shows the air under an arch) andelevation:north/east/south/west(a region seen from the side, lit). Both also work part-way through the stack (upTo). A new recipe,terrain-arch-cliff, is a cliffed mesa with an arch, a shelf and a spire."} - {"area":"api","text":"ctx.animator.bone(name, pose) reads a bone's world position and rotation: the drawn pose, or the clips' pose before IK for measuring foot targets. (API since 0.7.0)"}
- {"area":"api","text":"A new built-in behaviour, sway, gives a visual child of a moving thing (a kart's body, a boat's cabin) spring-damped pitch, roll and bob from how its parent speeds up, turns and lands, without touching physics."}
- {"area":"api","text":"The query server answers where a world point is on screen and which world ray a screen pixel is: GET /camera/project?x=&y=&z=|entity=&view= and GET /camera/ray?x=&y=&view=, per split-screen view, in the pixels of that view's cell (the answer says the cell size). They use the same projection as ctx.camera.worldToScreen and screenToRay. A view that is not live is refused as camera-view-unknown and a missing or non-finite point as camera-point-invalid."}
- {"area":"api","text":"Scripts can turn a screen position into a world ray: ctx.camera.screenToRay(x, y, view?) answers the ray through that pixel of a view (any split-screen view), and ctx.camera.pick(x, y, opts?) answers the first collider along it, with an optional ground plane (ground: height) when nothing is hit. Both go through the matrices the view is drawn with, so the pixel you aim at is the pixel you see. ctx.camera.worldToScreen(point, view?) is the inverse: the pixel a world point is drawn at (null behind the camera; off-screen points answer pixels outside the view)."}
- {"area":"api","text":"Scripts can send an event to one entity with ctx.events.emitTo, and ctx.world.query can return the nearest matches first with sort: \"distance\" and limit, so a game where many things message each other no longer stalls on busy ticks."}
- {"area":"api","text":"GET /feel audio now lists every mixer bus with its linear volume and mute state, including buses a project declares."}
- {"area":"api","text":"
@argus/gameplayhas helpers for a race HUD:raceClock(seconds, decimals?)writesm:ss.mmm(cut, not rounded, so a clock never shows a time not yet reached),raceDeltaa signed gap (-0.456,+1:02.500),ordinalEn/ordinal(n, locale?)a place (1st,2nd,3rd,11th;2.for a non-English locale until the locale layer has ordinal rules), andminimapPoint(position, bounds)theleft/toppercentages that put a marker on a top-down minimap image."} - {"area":"api","text":"Scripts can read where the mouse points: ctx.input.pointer is { view, x, y } (the split-screen view under it and pixels of that view's cell, exactly what ctx.camera.pick takes) or null. It is recorded with the tick's input, so a replay plays the same pointer and a script may decide gameplay with it. POST /input takes a pointer event ({ \"type\": \"pointer\", \"x\", \"y\", \"view\"? } or \"off\": true) to give a headless run one. Replay files are now format 3, which adds an optional pointer line written only when it changes; format 1 and 2 files still play and save back byte for byte."}
- {"area":"api","text":"Models with morph targets (blend shapes) now animate them: clip curves play through the animator's states, crossfades and layers, scripts can hold a channel with ctx.animator.setMorph(name, weight) and read it with morph(name), and GET /entities lists the moving channels under anim.morphs. (API since 0.7.0)"}
- {"area":"api","text":"
playAnimnow sets the character's animator state (by name), NPC types can declare movement animations (movement.anims: idle, walk, run) that follow the speed they move at, a custom action now reaches scripts as an npc.custom event, and NPC types that see \"players+others\" can now see NPCs of other types."} - {"area":"api","text":"GET /npc/log?id= serves one NPC's decision log (last 16 decisions, oldest first, each tick, action, rule, target); 404 when the id is not an NPC, 400 without an id. Needs the observe capability. (API since 0.7.0)"}
- {"area":"api","text":"NPC types: write a character's senses, rules and actions as one TypeScript file with npc() from the gameplay package, attach it like a behaviour, and the engine runs thousands of them deterministically: for one engine build, the same inputs give the same results whatever the thread count (the NPC test goldens also match on Linux, Windows and the web build). (API since 0.7.0)"}
- {"area":"api","text":"Admin console: the Waitlist page has \"Invite someone directly\", which makes a one-time invite link to a personal workspace for someone who never joined the waitlist (POST /api/admin/invites/personal). A matching pending sign-up is marked invited."}
- {"area":"api","text":"Admin console: inviting from the Waitlist (one sign-up, a batch, or someone directly) can email each person their invite (\"Email the invite\", on by default when invite emails are set up), and every pending invite (Waitlist and People) has \"Email invite\", with \"Emailed <when>\" above it once sent (\"Email again\" after that). A mail problem never blocks the invite: the console says what happened and still shows the link. The invite email is redesigned: what the engine does, what to try first, and three steps to get going, with a Download the launcher button (the download gate now also takes a live account invite code at /setup?invite=)."}
- {"area":"api","text":"A pickup can now push or boost the kart that drove over it. A trigger's
otherhasother.body(impulses, forces, velocity) andother.vehicle(its readings, andboost), andvehicle.boost(speed, seconds)gives any vehicle a drift-style speed boost. Another entity's vehicle can't be driven or reset this way (vehicle.not-own)."} - {"area":"api","text":"The race kit's countdown can hold the player's kart still until GO!:
startCountdown(ctx, { hold: \"countdown\" })switches the scene to an input context with nothing to drive with (declare\"countdown\": {}inmeta.input.contexts) atstart(), and back to the one it found at GO!. Run it from the player's kart or spawn (a prop has noctx.input). AGENT.md now namesroad-driver'sstartOnandstopOn, which hold a rival the same way."} - {"area":"api","text":"A character whose skeleton follows a known naming convention (Mixamo, the Mannequin rig, the common humanoid layout and VRM, VRoid, Character Creator and ActorCore, Blender and Rigify, 3ds Max Biped) now gets its retarget map from the import, so it plays the built-in clips without a hand-written map."}
- {"area":"api","text":"
ctx.world.road(id).progress(entity)andstandings(): laps and race order kept by the engine, with no lap counter in the game. The firstprogresscall starts tracking an entity on that road, and from then on the engine steps it every tick. It answerss,offset,lap,distance,nextGate,wrongWayandplace;standings()lists the tracked entities 1st first. Laps count at the road's gates in order, so reversing over the line and driving over it again is the same lap, and cutting past a gate or teleporting earns no lap. A world snapshot keeps the tracking (road_progressinGET /snapshot), so a restore, in the same world or a fresh one, goes on with the same laps and places."} - {"area":"api","text":"Behaviours can read the scene's water and wind: ctx.water.sample(x, z) gives the surface height, normal, velocity and kind (sea, lake or river) or null, and ctx.wind.sample(x, y, z) gives the air's velocity, both exactly as the engine floats bodies on them, so a replay reads the same numbers."}
- {"area":"api","text":"Snapshots carry an optional spawned list of runtime-spawned entity definitions, so a restore can recreate entities spawned before a scene load."}
- {"area":"api","text":"The built-in sway behaviour takes kicks: named game events (a hit, a boost) shove its springs, so a rider or a body flinches and settles without a clip. A data field can set the side and the strength, and by default only the entity's own vehicle's events count."}
- {"area":"api","text":"A terrain load now reports how long each stage took (file decode, cache read, evaluate, mesh, upload, collider, prewarm) in the run's load log and as
terrain_loadonGET /perf, with how many cells came from the cache and how many were computed."} - {"area":"api","text":"
\"ui-focused\"bus event andctx.ui.focused(screen?). Each focus move on a screen (arrows, pad, Tab, a click, or the first focus when a screen comes up) is raised once, beside\"ui-activated\", as{ node, screen, id }(BusUiFocused).ctx.ui.focused()returns the qualified id of the focused node, or null. Additive: a game that does not listen sees nothing new. Not served by the browser runtime yet (docs/UI.md, \"Hearing a focus move\")."} - {"area":"api","text":"
ctx.ui.fx(id, preset, { duration?, delay? })plays one of the UI motion presets (pop, slam-in, stamp, shake, ...) once on one node, so a behaviour can make a number pop or a banner slam in without adding and clearing a class. Paint only, never seen by the simulation or replays, and nothing under reduced motion."} - {"area":"api","text":"A race HUD kit in
@argus/ui/components:RacePosition(2nd / 8, the podium places in medal colours),RaceTimer(the clock, last and best lap, and the gap to the best),BoostMeter(a drift's boost charge with tier notches, built forctx.vehicle.driftChargeanddriftTier) andItemSlot(the held item, with a roulette). Each has a gallery screen andengine ui add <name>installs it.@argus/gameplayaddsrouletteItem(elapsed, names, landOn), which says what an item roulette shows at each moment and where it lands. A prop spec can now list\"null\"as a kind, for a prop whosenullmeans \"not yet\". Nothing that already existed changes."} - {"area":"api","text":"
Minimapin@argus/ui/components: a top-down map of a world area (bounds, metres;minXat the left,minZat the top) with an optional picture (src) and one marker per racer, coloured by--race-player-1..8and drawn larger for the player.@argus/gameplayaddsminimap(ctx, { bounds }), whoseplace(marker, position)moves a marker withstyle:leftandstyle:topand skips one that has not moved; eight moving markers cost about 0.1 ms a frame. Nothing that already existed changes."} - {"area":"api","text":"The race kit's moments in
@argus/ui/components:StartCountdown(3, 2, 1, GO!),RaceBanner(FINAL LAP, WRONG WAY, NEW RECORD),RaceResults(the finishing order, the podium rows tinted, a did-not-finish row) andRacePodium(the top three on plinths, each with an optionalmodel-viewof their kart).@argus/gameplayaddsstartCountdown(ctx), which counts down, playsstampon each step and raisesrace-goonce, andbanner(ctx), which slams a banner in and takes it down after its time; both are driven byupdate(dt). The library's strings gain sixui.race.*keys. Nothing that already existed changes."} - {"area":"api","text":"A race HUD recipe,
fixtures/recipes/race-hud(argus://recipes/race-hud): the race kit's components on a two-kart, two-lap oval, with the countdown, place, clock, boost meter, item roulette, minimap, FINAL LAP banner and results all driven by one behaviour through@argus/gameplay's helpers.docs/UI.mdhas a \"The race HUD kit\" section opening with the one-line import.RaceTimerwithdelta: nullnow draws an empty gap node a behaviour can fill once a lap ends, aslastandbestalready did; omittingdeltastill draws none."} - {"area":"api","text":"Fourteen colour names for race HUDs, defined by every built-in theme and the engine's own table:
--race-place-1..3(gold, silver, bronze),--race-boost-tier-1..3and--race-player-1..8, with two new palette steps,--gold-400and--bronze-400. They are the same in every theme; a game restyles them in its own@theme. Nothing that already existed changes."} - {"area":"api","text":"
GET /ui/statsshows what the game UI costs and why it laid out: the frame's UI time, draw calls, quad rounds, quads and text runs, and per screen its node count, layout passes and what dirtied layout last (textonhud:place, astylescascade, atransition).GET /perfgainsui_msandui_draw_calls, and the flight recorder gainsuispans with aui.layout:<screen>:<cause>marker per screen that laid out, recorded only while it is on. Finding a HUD that lays out every frame, or a shadow that splits the UI into extra draw calls, is now a read instead of a bisect."} - {"area":"api","text":"Vehicles report their air time and their last landing (how many, how hard, how long in the air) to scripts, for landing effects and sounds. (API since 0.7.0)"}
- {"area":"api","text":"
ctx.vehicle.waterreads a watercraft's last tick for wakes, spray and sounds: speed through the water, how far it is planing, how much of the hull is under water, the bow and whether it is wet, the thrust, capsize, and a slam when the hull hits the water hard."} - {"area":"launcher","text":"You can delete your account yourself: Account ▸ Delete account on the accounts site lists exactly what is deleted and what is kept, asks you to type your email address, and signs you out everywhere at once. Your personal data is erased 30 days later; sign in again before then and your account and data come back. If you are the only owner of a team, hand it over or close it first (the team page now has Close). Account ▸ Download my data gives you everything as one JSON file first. Cancelling a subscription is a separate page that touches billing only, never your account or data (there is no billing during the beta). The Privacy Notice now says how deletion works and what is kept (version beta-2026-10-25): you are asked to accept the terms once more, in the browser or the launcher."}
- {"area":"launcher","text":"Open with AI now says that Claude Code asks before using the Talos tools the first time (and the one flag for scripted runs, --allowedTools), and has an optional box, off by default, to let Claude use them without asking; it adds one rule to the project's own .claude/settings.local.json. The command line has --allow-tools for the same."}
- {"area":"launcher","text":"An offline animation converter turns FBX, BVH, glTF and Blender clips (Mixamo, CMU, Rigify and Quaternius rigs) into GLB clips on the canonical humanoid, with rest-pose alignment, an events sidecar from Blender markers and contact-sheet previews."}
- {"area":"launcher","text":"The animation converter recognises the common mannequin bone names (pelvis, spine_01, clavicle_l, ball_r and so on, with three or five spine bones), so those clips convert onto the canonical humanoid without a hand-written map. Clips on tiptoe now stand on their toes instead of being lifted off the floor."}
- {"area":"launcher","text":"The launcher has a Guides page under Learn: connecting Claude Code (Windows or WSL, with what to do when the tools do not start), exporting and sharing a game, and reporting a bug with exactly what a report sends. The guides are text from the Start here guide and work offline. Start here also gains a \"Share your game\" section, and no longer says screenshots can be attached to a report (there is no screenshot option)."}
- {"area":"launcher","text":"The launcher has a Help section in its left-hand menu with links to the website: Website, Getting started, Known issues and How to report bugs. They open in your browser. The Report a bug form links to how to report bugs, and gives the email address to use if sending from the launcher does not work."}
- {"area":"launcher","text":"The Launcher signs you in to your Talos account: press Sign in on the Projects tab it opens on (or on the Engine tab, or in Settings ▸ Access), then approve the code in your browser with the account your invite was sent to, and type its last 4 characters. Nothing is pasted, and the Launcher downloads with that sign-in. A tester token, under Use a tester token instead, works until you sign in with your account; after that, use Sign in."}
- {"area":"launcher","text":"The launcher writes how long its window took to come up to its log, once per start: when the window, the graphics device and the first frame were ready, in milliseconds (a line starting \"started:\" in argus-hub.log)."}
- {"area":"launcher","text":"The launcher's upgrade dialog can now upgrade a project whose files need converting: Upgrade project to Talos X runs that engine's
project migrate --apply, which keeps a backup of every file it changes. The result offers Open with Talos X and Restore the backup. Later, the project's engine menu offers Undo the upgrade… while that backup is the newest. This needs an engine that can apply upgrades; with an older engine the dialog stays a preview."} - {"area":"launcher","text":"The Engine page lists other versions you can install, shows how big an update is, has Update all, marks a version Verified with the date, and keeps Open folder, Verify, Repair and Remove in a ... menu on each version."}
- {"area":"launcher","text":"Select a project in the launcher and press Open with AI: it writes the project's .mcp.json and approves the Talos tools in the project's own .claude/settings.local.json before your AI starts, then shows the one line to run, with a Copy button. There is nothing to restart, and nothing outside the project folder is changed."}
- {"area":"launcher","text":"Every project has its engine version: projects made in the editor record it, and a card without one has Use, which records the newest installed engine."}
- {"area":"launcher","text":"When the Samples list has a newer version of a sample you have installed, its card says so and offers Get, which installs the newer version as a second project (named with its version) and leaves your copy and your edits alone."}
- {"area":"launcher","text":"A new sample on the Samples page, Kart Starter: a kart on a loop track. Drive, drift through three boost tiers, then change the kart's settings in Details and Play again. It needs Talos 0.7."}
- {"area":"launcher","text":"A new sample on the Samples page, Twin Trail: couch co-op for one or two, where a second player joins any time with a controller in split screen. It needs Talos 0.7. A sample card whose engine version is not installed now says so and offers the Engine page, instead of an Install that would be refused."}
- {"area":"launcher","text":"The Samples page now has three small games to install and open: Hop Lane (a 3D arcade game), Pebblewind Heights (a 3D platformer) and Lantern Hollow (a 2D platformer)."}
- {"area":"docs","text":"docs/ANIMATION.md: the way in to animation for a newcomer. Import a model, make it move with no script, drive it from a behaviour, transitions and what fires them, blend trees, loops, one-shots and events, the body rig for a model with no skeleton, and a table of common mistakes with the message each one gives. Every example is run by a test, and agents read it as argus://docs/animation."}
- {"area":"docs","text":"docs/ANIMATION.md has a section on models animated by moving their parts rather than a skeleton (a door, a lid, a fan): Import gives them an animator, the parts ride their nodes, a skinned character's props ride its bones, and what the node-animation import warning means. Its example is run by a test like the rest of the guide."}
- {"area":"docs","text":"The editor guide has a \"Buildings and streets\" section (Create ▸ Building and Street, the engine's own kit, importing kit pieces), START-HERE points to it, and the agent guide has a recipe for houses and streets from the engine's kit."}
- {"area":"docs","text":"A new page,
argus://docs/script-performance(docs/SCRIPT-PERFORMANCE.md), says how to keep behaviours cheap with the API as it is: let the query find the nearest, read positions in one call,emitTo,updateAll, number locals. It has measured costs; on the 200-bot arena the first pattern alone makes the script five times cheaper."} - {"area":"docs","text":"docs/FOLIAGE-PRESETS.md: the foliage presets, the one-line
foliage.presetcall and its CLI form, what it writes, re-runs, undo and budgets; served in the agent pack (explain/search) asfoliage-presets. The agent guide listsfoliage.preset."} - {"area":"docs","text":"A sunny-midday look preset: the
look-sunny-middayrecipe (alsoargus://recipes/look-sunny-midday) holds a scene's sky, sun, haze, clouds, tonemap and grade for a bright, clear midday in one block to copy, and docs/LOOK-PRESETS.md lists it. It uses existing settings only; scenes that do not copy it are unchanged."} - {"area":"docs","text":"Browser and desktop players can share a networked match; docs/API.md lists what a desktop player's scripts give up in such a match (the members the browser does not serve yet), and docs/NETCODE.md says how the two are kept in step."}
- {"area":"docs","text":"A walkthrough, docs/KART-RACE.md: make a kart race in 15 minutes from the Kart Starter, with a rival on the built-in
road-driver, a chequered start line, the sunny-midday look, a terrain with roadside plants, a baked minimap and the race HUD kit. Every step is a tool call or a command; the agent reads it asargus://docs/kart-race."} - {"area":"docs","text":"A new Features page (docs/FEATURES.md) lists every package with its Stable, Beta or Experimental label, and release notes gain a Feature maturity section; both are generated from the engine's feature list. The roadmap never shows a picture or video on an Experimental item."}
- {"area":"docs","text":"Writing scripts for multiplayer (docs/MULTIPLAYER-SCRIPTS.md, also on the docs site): multiplayer is not in this build yet, so the page gives the rules scripts will run under once it arrives in plain words, with the fix for each: ctx.time.after instead of async, Math.pow instead of **, emitTo for one entity, a list instead of deep recursion, and settling hits by entity id"}
- {"area":"docs","text":"The friends guide says how to update to a new tester build: how the launcher offers an update, what happens to projects, saves and the previous engine, how to go back to it, what isn't supported yet, and what to do when an update fails"}
- {"area":"docs","text":"START-HERE has a What's new for testers section: events for one entity, scripts that can't break each other, 2D on the high-definition renderer, and, marked in testing, faster first launch of exported games and the browser version matching the desktop; the friends guide points to it"}
- {"area":"docs","text":"Three small OFL starter fonts (Inter Regular and SemiBold, JetBrains Mono Regular) ship under fixtures/render/fonts for new projects to copy into ui/fonts."}
changed
- {"area":"editor","text":"API keys for the generation services now live in Edit > Editor Preferences > API Keys. Each service has a row showing whether a key is set, a masked field to paste one, Save and Clear. Keys are yours, kept on your computer and never in a project. Project Settings shows each key's status and an Edit keys… button that opens that page."}
- {"area":"editor","text":"Deleting a prefab file from the Content browser now also names the prefabs that nest it and the scenes that reach it through them. The workspace log's prefab entry counts those scenes too."}
- {"area":"editor","text":"The editor opens faster: its GPU device is set up while the window and the project are being created, instead of after them (about 60 ms less on an RTX 3080; set ARGUS_GPU_PREWARM=0 to turn it off)."}
- {"area":"editor","text":"The editor's embedded component schema may now be up to 64 KB (was 60 KB), for the Details panel's field hovers and the vehicle handling, recovery, contact and off-road settings; the commander approved the raise (#11265)."}
- {"area":"editor","text":"The foliage brush now sits at the top of Details when a foliage layer is selected, above its other settings, so you no longer scroll to find it."}
- {"area":"editor","text":"The material panel's HD preview shows its first picture much sooner: it is drawn without ray tracing first, with a \"Full lighting loading…\" note under it, and replaced by the full ray-traced picture once that renderer is ready. If full lighting cannot start, the note says so and why."}
- {"area":"editor","text":"The body rig's clips are stronger (version 2): a lean tips the body 36 degrees from the hips up instead of 17, Throw winds up 45 degrees before it swings 45 the other way with the body leaning out, and ThrowBack turns over the shoulder leaning back with the face kept toward the camera. A model already rigged keeps its clips and plays as before; reimport it from the original file to get the new ones."}
- {"area":"editor","text":"A model imported through the Import dialog (from the file picker, or dropped on the window from the file manager) lands at the centre of the view instead of at the scene's origin, where it sat on top of the last import and the player."}
- {"area":"editor","text":"A .glb that keeps its textures as picture files beside it now imports, with the pictures packed into the project's copy, as a .gltf with its files beside it already did. It used to be refused with \"export a .glb with its textures embedded\"."}
- {"area":"editor","text":"A file the editor will not import is now named on the status line by its file name (\"Kiste.glb is not a glTF or GLB file…\"), with the full text, folders included, on hover. The refusal is also an Activity row under Failures, so Failures no longer says (0) beside it."}
- {"area":"editor","text":"The material panel's preview no longer turns each picture into a PNG and back. It takes the pixels straight from the capture, which makes each redraw about 23 ms faster in HD (8 ms in the standard renderer). On Triton's RTX 3080, an edit now shows in about 88 ms in HD (it was 111) and 22 ms in the standard renderer (it was 48).
POST /captureand the agent'sshader.previewstill return PNGs."} - {"area":"editor","text":"The editor's first window opens at most of the screen instead of 1280x720, so the panels are not squeezed on a large screen;
--window-sizestill sets an exact size."} - {"area":"editor","text":"Parents in the Outliner now have a caret to collapse and expand them (Alt+click does everything under them), selecting an entity in the viewport opens its parents and scrolls to it, search results show the parent they sit under, and the list stays fast in scenes with thousands of entities. The Outliner opens taller, and Ctrl+D duplicates an entity together with its children."}
- {"area":"editor","text":"Add component > Particles now adds the library look (builtin:fx/sparks); a particles component's Effect is one picker for the library presets and your .vfx.json files, and the old preset shows as Simple preset with a hint."}
- {"area":"editor","text":"Play no longer runs while the newest build has failed: it says which file and line failed, instead of quietly running older code from the last good build. \"Play last Ready\" still runs the last build that worked, on purpose."}
- {"area":"editor","text":"Play now runs the scene you have open, even with unsaved changes, with no prompt. It is labelled as an unsaved scene, nothing is written to disk, and the scene stays unsaved after you stop."}
- {"area":"editor","text":"Details shows the same \"New in the scene\" row when nothing is selected, and it and the Create menu draw one list, so both offer the same items and grey them out for the same reasons (a second Terrain names why). The row used to appear only under a selected entity's components, so with nothing selected there was no way to make a terrain. Foliage stays disabled until an object with a model is selected, and its tooltip says why."}
- {"area":"engine","text":"HD's aerial perspective under an atmosphere sky now dims each colour by the air's own transmittance, so distant terrain turns bluer with distance instead of fading to grey, and geometry far out near the horizon gets the full haze of its distance."}
- {"area":"engine","text":"The installed engine is about 1.7 MB smaller: the agent knowledge pack stores its two largest files, the document chunks and the search index, compressed (docs.json.zst and search.json.zst). The agent checks them against the pack's manifest as before and unpacks them in memory; its answers are unchanged."}
- {"area":"engine","text":"The animator pass runs on worker threads once a scene has 32 or more animated characters, with the same result on any thread count, on the web build's single thread too. It shares the controller pass's thread setting and pool, so setting that to one thread turns both off. Animation events raised on the same tick now arrive in entity-id order, not scene order, so a restored world or a late joiner hears them in the same order."}
- {"area":"engine","text":"Past the edge of an ocean bathymetry the sea floor now falls away as a shelf instead of dropping to deep water, so shoaling waves and the shallows' colour fade out instead of stopping in a straight line (the drawn sea and floating bodies agree)."}
- {"area":"engine","text":"HD rivers are a clearer, more reflective water: pools mirror their banks and the body is a dim teal over the bed instead of a milky cyan."}
- {"area":"engine","text":"More of what a person sees says Talos. A new install's default projects folder is
Documents\\Talos(an install that already hasDocuments\\Arguskeeps using it, and a folder chosen in Settings still wins). Crash reports name the program the way a person knows it (Talos editor 0.7.0 (argus-editor)), and the editor's entry in Add or remove programs links to the Talos website. Installs upgrade in place as before; nothing moves on disk."} - {"area":"engine","text":"Build Theatre cuts open on a one-second teaser of the finished build, never frame empty space, fill the frame (portrait by height), hold wide shots at most about three seconds before going in to a detail, and land big arrivals biggest-first; composed clips are loudness-normalised to -16 LUFS."}
- {"area":"engine","text":"Build Theatre shows a removed entity leaving: it swells a little, then shrinks and sinks away over 0.35 s, instead of vanishing between two frames."}
- {"area":"engine","text":"Build Theatre cross-fades a recoloured mesh from its old colour to its new one over 0.6 s, instead of switching between two frames; a swapped material still glows."}
- {"area":"engine","text":"Build Theatre's phase chip advances through the build (greybox, materials, lighting, effects, UI, gameplay) and never steps back; a coloured or modelled mesh counts as materials work; and captions in 16:9 and 1:1 are as big as in 9:16."}
- {"area":"engine","text":"The engine's command line is easier to start with.
argus --helpopens with a plain description and no longer lists the internal tools (theatre,serve-mockandprofile-tracestill run).argus project init <name>now makes a project from the New project templates (--template,--type,--dir) instead of pointing to another program.argus run --seconds Ssets a plain run's length in simulated seconds at 60 ticks a second, so--seconds 3is--frames 180."} - {"area":"engine","text":"A time-of-day preset's cloud layer (an atmosphere sky with a
presetand noclouds) now starts above the scene's highest terrain point, with 300 m to spare, so \"overcast\" over mountains is a deck above the peaks and not a grey sheet through the valley. A scene that writescloudskeeps its own layer."} - {"area":"engine","text":"HD clouds look more three-dimensional by default: lobed cumulus with flat dark bases and bright tops, wispier edges, flat decks that break into cells, rims that glow toward a low sun, a dusk deck brighter toward the sun than away, and brighter multiply-scattered light in sunlit cloud (clouds are about 0.4 times as bright on average, since they hold less volume). Setting ARGUS_CLOUD_DETAIL=1 also turns on opt-in high-detail clouds: a full-resolution, anti-aliased, finer-eroded cloud image for about 0.1 ms."}
- {"area":"engine","text":"A scene component written as a JSON array instead of an object (for example [\"mesh\", \"builtin:cube\"]) is now refused with a schema-shape error, as the TypeScript validator always did. Engine binaries are about 0.9 MB smaller."}
- {"area":"engine","text":"The project manifest's schemaVersion refusals no longer name the product. They now say \"this engine\", for example \"schemaVersion 2 is newer than this engine supports (0 to 1); open the project with the newer engine that wrote it\". The Rust and TypeScript checkers word them the same. A release export with no icon is refused the same way, naming the engine's built-in icon rather than the product."}
- {"area":"engine","text":"A character controller is now as wide and tall as its entity's capsule (or sphere) collider, instead of always 0.3 m by 1.8 m, so a body authored wider stops that far from walls; the navmesh's player agent, the camera's probe cap and
engine check's 2D path follow it."} - {"area":"engine","text":"Scenes with many characters step their character controllers on several threads by default, with exactly the same results on any number of threads: the machine's cores less one, at most 8, for 64 or more controllers (fewer run on one thread).
ARGUS_CONTROLLER_THREADS=1(orLoadOpts::controller_threads) keeps them on one thread. Controller events andcharacter-squeezednow reach behaviours in the order of the characters' scene ids rather than their load order."} - {"area":"engine","text":"HD ground cover: the upscaler's reactive mask marks only the near blades and the flowers, not the mid-distance single-triangle blades, which barely smear and cost as much to mark as to draw."}
- {"area":"engine","text":"Crash reports from the editor, the engine and exported games write the home folder and the user name as <home> and <user>, so a report can be shared without naming the person who sent it."}
- {"area":"engine","text":"A native game whose crowd runs on two or more threads now moves its navagents with the Rust crowd (the one the web build has), which is faster there; on one thread it keeps Detour's. Set the CROWD environment variable to detour (or rust) to choose. A deterministic session (LoadOpts::deterministic: networked or lockstep) always uses the Rust crowd, so a peer on one thread computes what a peer on four does."}
- {"area":"engine","text":"The Rust crowd scores its avoidance samples lane by lane and finds neighbours in a dense grid: the same results bit for bit, with less work per agent."}
- {"area":"engine","text":"The default look is back to agx-punchy in both renderers, with no -0.25 EV shift on HD's default auto exposure and no default grade (Sean #4169). HD no longer applies a default grade (it was contrast 1.1, then 1.2; Captain #4200), so the default matches the 30 Sep look; name a
lookwithcontrastandsaturationto grade a scene. Nameagxfor the base curve."} - {"area":"engine","text":"HD scenes now adapt their exposure automatically by default and get a slightly richer default colour grade, so shaded streets and sunlit vistas both read without hand tuning. A scene that sets its own
exposure, the retro style, orexposureMode: \"manual\"keeps its fixed exposure, and a scene that names alookkeeps that look. At night, auto exposure lifts at most two stops above the manual exposure, and a scene switch exposes the new scene at once."} - {"area":"engine","text":"On Windows the editor now runs inside argus.exe (argus editor), and argus-editor.exe is a small windowless stand-in that starts it, so the install is about 32 MB smaller; shortcuts, the file association, the launcher and the agent's editor.start work as before, and the editor shows as argus.exe in Task Manager."}
- {"area":"engine","text":"The JavaScript the host embeds (the web runtime, the road line and script math helpers) ships minified (whitespace and comments only), about 11 KB less of the web module gzipped; the networked determinism digest changes once, so peers of a release still agree."}
- {"area":"engine","text":"A project that opted into an Experimental feature keeps validating once that feature is promoted: an \"experimental\" entry naming a Beta or Stable feature is now a warning (project-experimental-promoted) that says to remove it. An id that names no feature is still an error."}
- {"area":"engine","text":"Exporting for the other platform (Windows from Linux, or Linux from Windows) now finds that platform's export tools in the install's sdk/targets folder or your export-targets store as well as beside the editor, packs that platform's own engine and launcher, and when they are missing names both files and every place it looked. Native exports now report their size against the engine and download budgets, and warn when the download is over 20 MB."}
- {"area":"engine","text":"An exported game no longer unpacks itself on first launch: it is read straight out of its executable, and only the engine is unpacked, once, shared by every update that keeps it. Folders of builds nobody launched for 30 days are cleaned up (ARGUS_EXPORT_KEEP=1 keeps them)."}
- {"area":"engine","text":"ARGUS_REQUIRE_EXPORT_BIN=1 makes packages/export's shader-pack tests and its every-sample export fail when the release argus-export is missing, instead of skipping, so a gate that never built it cannot pass them without running one (docs/CI.md)."}
- {"area":"engine","text":"HD's auto exposure now brightens a dark scene only 0.6 of the way to mid-grey below EV100 15 (a forest interior reads about 1 EV darker; open daylight scenes are unchanged), for scenes that leave exposure to the engine. A scene can set
meta.render.exposureAdaptation(strength,referenceEv100) to tune it; strength 1 is the old full adaptation. Scenes that setexposureorexposureMode, and the retro style, keep what they had."} - {"area":"engine","text":"The fern preset is now Beta: it is on without an experimental opt-in, and a project that still lists foliage/fern-preset gets a warning to remove it."}
- {"area":"engine","text":"Generated broadleaf crowns (oak) grow as leaf clumps with sky pockets between them (new crownGaps parameter), and crown interiors are less dark: the baked crown shading is halved because ray-traced lighting already darkens the interior."}
- {"area":"engine","text":"The generated fern is now a low woodland rosette about twice as wide as tall, with lighter young fronds at the centre, a few dead brown fronds lying on the ground (deadFronds) and coiled fiddleheads on young plants (fiddleheads); dead fronds and fiddleheads stay nearly still in the wind. A large Bracken template is added for clearings and woodland edges."}
- {"area":"engine","text":"Generated plants now carry their baked crown shading as a separate vertex attribute instead of darkening the leaf and bark colours, so crowns are shaded once: by ray-traced lighting when it is on, by the baked term when it is off."}
- {"area":"engine","text":"Foliage presets draw far fewer models: each op caps the template variants it uses (
variantsin the preset file: trees 2, shrubs and ferns 1), folded after the cook so positions and spacing are unchanged. Over 200 m the presets cook 8-14 models instead of 46-88, and their triangles are tuned in the data (younger trees, lighter mixes, lower density) to 2.9-4.3M full-detail triangles instead of 3.4-19M.meadow,pine-forestandbroadleaf-woodnow keep off the scene's roads (trees 3 m, shrubs and ferns 1 m), asroadside-vergealready did. Inpine-forestandbroadleaf-woodthe understory now culls at 80 m and 70 m, which keeps both at about 1.1-1.2M triangles drawn from a ground camera."} - {"area":"engine","text":"Generated trees with impostor hints draw as virtual geometry from 10,000 triangles (was 25,000), so young and mid-size trees in a forest take the faster foliage path with impostors at distance instead of drawing every leaf card at full detail. Generated trees now carry the impostor hint by default (set outputs.impostor to false to turn it off); grass, ferns, flowers and shrubs still get it only when asked."}
- {"area":"engine","text":"Scripts can no longer patch built-ins (Array.prototype.map, Math.random) or the shared ctx objects (ctx.world.find) for every other script in the game; such a patch throws a TypeError. Naming a script's own errors and overriding toString on its own objects still work."}
- {"area":"engine","text":"The built-in
swayandpathbehaviours do their maths on plain numbers instead of building and unpacking a small array for every vector and quaternion step, andpathreads the entity's size only whengroundorrollneeds it. They give exactly the same positions, rotations, state and events as before; they just cost less script time a tick."} - {"area":"engine","text":"A 2D game on the HD renderer no longer pays for global illumination it cannot use: a frame whose every surface is unlit (sprites, tilemaps, unlit shaders) skips GI and looks exactly the same, 0.6 to 1.2 ms faster on an RTX 3080 at 1080p. The
rayTracing.giAlwaysquality setting keeps GI on."} - {"area":"engine","text":"HD plants keep their crown occlusion with ray-traced GI on once they are past the GI's probe volume, ramping in from half its reach (25 m by default) to all of it (50 m), and far impostors take their tree's mean crown occlusion the same way. Distant forests no longer take the open sky through every crown and read mint-teal. Near trees, which the GI occludes itself, are unchanged.
HdSettings::crown_occlusion_beyond_gi(on by default) turns it off."} - {"area":"engine","text":"HD's entity-id and depth pass draws a far, 400-triangle copy for virtual-geometry meshes that are under 64 pixels wide, as it already did for raster meshes, so a distant forest costs far fewer id-pass triangles; ids are unchanged."}
- {"area":"engine","text":"HD reserves GPU memory in smaller blocks, so a scene with many large textures and buffers (a forest) no longer holds half a gigabyte of unused memory: the video memory and process memory the game reports fall with what the scene allocates. Frame times do not change. A forest's impostor atlases also no longer carry spare layers."}
- {"area":"engine","text":"HD waterfalls are rebuilt: the falling water is layered, see-through where thin and white only where thick and aerated, breaking into strands as it falls; spray and mist at the foot no longer white out a nearby camera; the plunge pool keeps its water colour; river edges fade softly into the bank."}
- {"area":"engine","text":"The install is 6.9 MB smaller: the SDK's esbuild ships compressed and is unpacked, checked against its recorded hash, into the user's cache the first time the engine starts (about 0.15 s once)."}
- {"area":"engine","text":"The Linux install is 17 MB smaller: the SDK's private Node runtime ships without its symbol and debug tables. The install checks the stripped runtime against the SDK's own manifest, and its notices name the upstream Node.js binary it was made from."}
- {"area":"engine","text":"The install is 2.7 MB smaller: the SDK's TypeScript compiler ships compressed and is unpacked in memory when a check or the engine CLI first needs it (about 25 ms; nothing is written to disk)."}
- {"area":"engine","text":"The vehicles guide now walks through a kart on a track from start to finish: the kart's collision box and wheels, the road, counting laps from the gate events (with what each event carries), putting the kart back on the track, and a self-test that steers it. The driving-course recipe no longer says there is no vehicle component; it points to the kart guide for a car with real wheels."}
- {"area":"engine","text":"The standard renderer (native) keeps a still instanced mesh's rows on the GPU: once a set has not changed for
KEEP_STABLE_FRAMES(30) frames its rows are uploaded once into a region of the instance buffer, and each frame draws its visible cells from them by ranges instead of rebuilding and re-uploading every visible row. Any change (instances, transform, material, visibility) sends it back to per-frame rows at once. Frames are the same bytes either way; the region is capped atKEPT_ROWS_MAX(1M rows) and packs down when dropped sets leave more thanKEPT_COMPACT_FREE_SHARE(25%) of it empty. The web build and HD are unchanged."} - {"area":"engine","text":"The Linux archive is 46 MB smaller: its editor is folded into the
argusbinary as on Windows, withargus-editora small forwarder toargus editor. Its SDK also ships esbuild and the TypeScript compiler packed when the checkout supports it (9.4 MB more)."} - {"area":"engine","text":"The Linux archive installs 19.4 MB smaller: the SDK's Node ships without its symbol and debug tables (when the source tree's packer can strip it), and
argus-wadships compressed and is unpacked by the launcher the first time a recipe needs it, as on Windows. The smoke test now checks thatargus-wadunpacks to its recorded hash and runs."} - {"area":"engine","text":"The Linux archive is held to the same installed-size gate as the Windows install: a 250 MB cap, at most 2% growth over its recorded size (192.28 MB), no binary of 100 MB or more and no large duplicate files. The gate's per-binary check now covers Linux executables too."}
- {"area":"engine","text":"- A scene that
argus validaterefuses for the contract's length and range bounds (a foliage layer with more than 32 prototypes, a density of 0,players.maxover 4) still loads, and now says so: oneargus: warning schema-shape <pointer>line for the file, with validate's message for the first value out of bounds and how many more there are.argus run, a script'sloadScene, F5 and the file watcher all say it. Nothing else about the load changes."} - {"area":"engine","text":"- The editor's control endpoint (
--control-port, on the launcher too) andargus run --serve(the query API andWS /stream) answer only programs on this machine. A request must address the server as127.0.0.1:<port>orlocalhost:<port>(Host), may carry noOriginbut the server's own, and must send a POST body asContent-Type: application/json. Otherwise it is refused:403 host-rejected/host_rejected,403 origin-rejected/origin_rejected,415 unsupported-media-type/unsupported_media_type(the editor's codes are kebab-case, the query API's snake_case). Before, a web page the person had open could drive the editor (save, import, commit through a cross-sitetext/plainPOST), read a served game through DNS rebinding, and open its live stream. The CLI,argus-agent, Node'sfetchand curl send what the rule wants and are answered as before; a client that sets its ownHost, or calls from a browser page on another origin, is refused. The workspace service's existingHostcheck is the same function (argus_query::loopback)."} - {"area":"engine","text":"A navmesh tile is partitioned monotone by default instead of layers: a level tile where walkable tops stand over a floor (a pillar field, shelving) built in about 0.1 s instead of up to 1.9 s, and open terrain builds as fast as before with the same paths. Tile meshes change slightly (the 4 km terrain: 7,072 to 7,083 polygons). Layers can still be chosen (AgentParams::partition); single-tile meshes are unchanged (watershed)."}
- {"area":"engine","text":"NAV_BUILD_THREADS (or, when that is unset, RAYON_NUM_THREADS) now caps the workers a tiled navmesh build runs on when nothing else sets the number: the default for a wide level, and any build asked for the machine's parallelism. A shared build box or a test run can keep these builds to a few cores without code. The navigation tests now build on 2 to 4 workers instead of every core."}
- {"area":"engine","text":"Editing a static collider in a level wide enough for a tiled navmesh now rebuilds only the tiles the change can reach, not the whole level: moving one long wall on a 1000 m x 700 m level rebuilds 24 of 192 tiles in about 70 ms instead of about half a second, and the result is exactly the mesh a fresh load of the edited level builds."}
- {"area":"engine","text":"A wide level's tiled navmesh build now runs on every core but one by default, not on every core, so the game's loop and audio keep a core while it loads; LoadOpts::nav_threads sets the number. A kilometre-square level loads in the same 0.55 s on a 32-core machine (7.96 s on one worker)."}
- {"area":"engine","text":"HD's atmosphere sky now reads as a dim moonlit night with the sun well below the horizon (the
nightpreset, or any sun below about -4 degrees): a cool moon light opposite the sun that casts shadows, and a dark blue dome in the sky and the ambient light, fading in between -4 and -10 degrees; frames with the sun above -4 degrees are unchanged."} - {"area":"engine","text":"NPCs sent to a point with act.moveTo now walk round walls and obstacles by a flow field, as they already did when following an entity, instead of sliding along a wall in the way; a point in a clear straight line is still walked straight. Paths of NPCs that moveTo points behind obstacles change."}
- {"area":"engine","text":"NPCs on act.patrol now walk round walls and obstacles to each waypoint by a flow field, as act.moveTo a point does, instead of sliding along a wall in the way; a waypoint in a clear straight line is still walked straight. Patrol routes with an obstacle between waypoints change."}
- {"area":"engine","text":"NPC events (
npc.attack,npc.noise,npc.custom) now reach behaviours in the order of the NPCs' scene ids, and name NPCs and targets by scene id (ev.data.npc,ev.data.target; they were entity indices). Ties between NPCs (two wanting one reserved spot, more than 64 custom actions in a tick) are settled by a hash of the tick and the NPC's scene id instead of favouring whichever NPC loaded first, so who waits rotates from tick to tick. The order is the same on any number of threads and on any machine; it does not depend on the order entities were created in."} - {"area":"engine","text":"-
onCollision(and the\"collision\"bus event) now fires once per pair of bodies, on the tick they start touching, as the hook was always documented (\"once when a contact starts\", the usualOnCollisionEnter). It used to fire for every contact point on every tick the bodies stayed in touch, several hundred calls a second for a body resting on the floor, and a game that queued them for anupdatethat had stopped running filled its script heap. A pair that separates for 3 ticks or more and touches again is heard again. A snapshot with the solver state carries which pairs are touching, so a restored world, or a fresh one a snapshot is loaded into, does not hear them start again. - New hookonCollisionStay(ctx, collision): every tick two bodies touch (the start tick included, afteronCollision), once per pair per tick, with that tick's strongest point. For games that react for as long as a contact lasts, such as a wall glance or a scrape. Not on the bus; a module without it costs nothing.MockCtx.collideStaydelivers it in tests."} - {"area":"engine","text":"Experimental features are now off in a project unless it lists them in \"experimental\" in its project file: waterfalls, the forest-floor ground cover and lip-sync. The load and the export say which ones are off and how to turn them on."}
- {"area":"engine","text":"An orthographic camera now frames the same 16:9 box at every window size, and
ctx.camera.viewSizereports that box measured in the 1920x1080 reference view instead of following the window, so a 2D game (andcamera-2d's clamp) plays the same in a replay at another size or on a co-op peer's screen. The window draws the least view that contains the box, so portrait and square windows show more above and below, wider ones more at the sides. ApixelsPerUnitcamera is drawn at the largest whole-number pixel scale that holds the box (below 1x only when even 1x is too big), andcamera-2d'spixelScalenow hands the engine its box withpixelsPerUnitas the art's texels a unit. At 1920x1080 nothing changes."} - {"area":"engine","text":"A world that adds a million static colliders at once builds its broad-phase tree on several threads: the binned build splits its two large halves across threads (parry3d, vendored with this one change; vendor/parry3d/PATCHED.md). The tree is the sequential one, node for node, at any thread count, so contact order, queries and determinism are unchanged. Web builds stay sequential."}
- {"area":"engine","text":"Loading a scene with thousands of static colliders (a forest of meshes, an instanced mesh) no longer stalls the first physics step as long: the broad phase builds its tree once instead of inserting every collider and then rebuilding. With 1,000,000 instanced trees the first step drops from about 2.3 s to 1.05 s, and peak memory from 0.87 GB to 0.72 GB (100,000 trees: 190 ms to 69 ms). Collisions and ray hits are unchanged."}
- {"area":"engine","text":"A scene's instanced-mesh models are now decoded on worker threads before the entities are wired, as plain meshes' models already were. A million-instance forest of four tree models loads about 0.24 s sooner (0.91 -> 0.67 s on Triton); the models and the world are unchanged."}
- {"area":"engine","text":"A game window started without a title, and the crash message box, now say Talos instead of argus."}
- {"area":"engine","text":"GET /schema now serves the query API's JSON Schemas from committed files in crates/query/schema instead of generating them in the running engine; the answers are unchanged, a test keeps the files equal to what the wire types generate, and the argus binary is about 0.5 MB smaller."}
- {"area":"engine","text":"
ctx.world.query({ tag })no longer visits every entity: the entity store keeps a tag index, kept exact by spawn and despawn, and a tagged query starts from it. Same entities in the same slot order; on a scene of ~850 entities the query costs a fraction of the scan."} - {"area":"engine","text":"A snapshot restore puts a behaviour's state back faster when its keys have not changed since the snapshot: the values are assigned in place instead of every key being deleted and added back. The restored state reads exactly as before, key order included."}
- {"area":"engine","text":"
ctx.world.road(id)'sat,closestandedgenow run in native code on the desktop engine: about a millisecond less script time a tick in an 8-kart race. The answers are the same bits as before, and the web build keeps the JavaScript versions; a side-by-side test keeps the two from drifting apart."} - {"area":"engine","text":"Ray-traced reflections no longer trace leaves, ferns and other thin foliage (materials with diffuse transmission): their glints did not survive the denoiser, and foliage-heavy views render faster. Those pixels keep screen-space reflections and the environment."}
- {"area":"engine","text":"navagents can walk on the pure-Rust crowd (the same result on any number of threads, ordered by scene id): always on the web, where there was no crowd at all before, and on desktop with LoadOpts::rust_crowd or the CROWD=rust environment variable. Detour's crowd is the desktop fallback (see crowd-b6-native-default) and keeps tiled navmeshes. World::set_crowd_threads(1) runs the Rust crowd on one thread."}
- {"area":"engine","text":"A script can no longer reach a function constructor through .constructor (it throws a TypeError), and in the browser MessageChannel, MutationObserver, BroadcastChannel and requestIdleCallback are hidden as they are natively."}
- {"area":"engine","text":"A scene edit from an agent, or through a prefab instance in the editor, now reads again only the entities it changed instead of the whole scene, so an edit to a large scene is faster; what is accepted and every error message are unchanged."}
- {"area":"engine","text":"meta.genre now accepts racing, platformer, top-down, side-scroller, puzzle and sandbox as well as third-person and first-person, and a genre the engine does not know is reported as an invalid value instead of 'saved by a newer version of Talos'."}
- {"area":"engine","text":"A behaviour's
performance.now(),Date.now()andnew Date()now read only the game's clock (ctx.time.now): every read in a tick returns the same value, andDatecounts from 1970-01-01, so a run and its replay keep the same values. Migration: a loop timed withperformance.now()inside one tick now reads 0 ms, so time it with the newctx.debug.wallMs()(real time, never for gameplay state); a script that usednew Date()for today's date, such as a save timestamp, now gets 1970 plus play time."} - {"area":"engine","text":"The other short number arrays scripts read (
entity.rotation,input.axisandaxisParts,water.sample'snormalandvelocity,wind.sample,environment.sunDirection, instance and poseposition/rotation) are made at their full length in one allocation, asentity.positionalready is. The same arrays and the same numbers."} - {"area":"engine","text":"Behaviour calls that pass JSON-like data (
entity.set,entity.component,ctx.events.emitdata and its delivery,ctx.ui.set, saves and timers) cross into the engine faster: the value is walked instead of printed and re-parsed, about 1.8 us less per call going in and 0.8 us less coming out, with the same values; anything unusual (atoJSON, a getter, a class instance, a cycle) still takes the old path."} - {"area":"engine","text":"Reading a position from a script (
entity.position,worldPositionand every other[x, y, z]the engine answers) makes its array in one step instead of growing it an element at a time. The array and its numbers are the same. On the 200-bot arena, whose behaviours read about 15,000 positions a tick, script time falls by about 13% (11.3 to 9.8 ms a tick on one core)."} - {"area":"engine","text":"Engine calls that return an object (a raycast hit, an input action's state, a vehicle's water state, road progress and standings, camera and pointer positions, and the rest) build it a little faster: each property name is looked up once per script runtime instead of on every call, about 0.045 us less per field, with the same objects and fields as before."}
- {"area":"engine","text":"The standard renderer now uses the same default tonemapper as HD (agx-punchy); scenes that name a tonemap are unchanged."}
- {"area":"engine","text":"The standard renderer now honours a material's specular and specularColor (as the high-definition renderer already did), in both the sun's highlight and the sky reflection: specular 0 takes the pale sheen off a matte surface seen at a grazing angle, such as a road ahead. Materials that do not set them look exactly as before."}
- {"area":"engine","text":"The standard renderer now draws particle flipbooks and velocity, up and custom facing that it used to ignore: an effect that declares them (a fire or smoke sheet, velocity-aligned sparks) animates and turns as it does in HD. Effects without them draw exactly as before."}
- {"area":"engine","text":"Seas and lakes on the standard and web profiles now draw animated, reflective water instead of a flat tint."}
- {"area":"engine","text":"The tick's CPU sea field is computed at the start of the tick on the ocean's own worker thread, while vehicles, physics and controllers run, so the first
ctx.water.sample(or floating body) of the tick no longer pays for the FFT on the main thread. Bit-identical fields; a sea nothing sampled last tick is not computed ahead."} - {"area":"engine","text":"A shipped game's engine now takes only what players and the export flow use (run, --info, --version, --help, --self-test and the window and quality options); development commands such as validate and the recording and watch options stay in the development engine, which makes the shipped binary smaller."}
- {"area":"engine","text":"The HD atmosphere sky looks better around the sun and at night: a soft glare around the sun, a starfield and a moon disc at night with the black band under the horizon filled in and the colours fading in the dark (bright lights keep theirs), clouds lit from below at dusk, and bluer shade under traced global illumination."}
- {"area":"engine","text":"HD's sky-first atmosphere pass (drawn when blended surfaces, particles or waterfalls are in the frame) now depth-tests against the read-only depth buffer, so only sky pixels run its shader and its cost follows the visible sky; images are unchanged."}
- {"area":"engine","text":"Snapshots (GET /snapshot) now carry each character controller's state between ticks (ground, anchor, carried speed, jump button, crouch, and the walk speed, gravityScale, moveWithGround and crouch a script set), and a restore puts it back, so a restored character steps exactly as the saved one: no landing on a restored floor, no second jump from a held button, still riding the lift it was on. Snapshots from older builds still load; their characters are put back standing if they were resting."}
- {"area":"engine","text":"Split screen no longer depends on the window's shape: the shared camera (ctx.views.shared) splits, merges and frames the same in a portrait, square or 16:9 window, and in a replay re-rendered at another size, because it decides in a fixed 16:9 reference view; a narrower window now shows more above and below instead of cropping players, and \"auto\" splits two players side by side even in a portrait window (say \"top-bottom\" for one above the other)."}
- {"area":"engine","text":"A game opens its window sooner: the first swapchain set-up now runs while the scene loads, and the default sky is built when the first frame needs it (about 260 ms less to the title on a Windows RTX 3080 test). Set ARGUS_SWAPCHAIN_THREAD=0 to turn the overlap off."}
- {"area":"engine","text":"An exported game with a telemetry endpoint baked in asks the player first (Yes / No, No the default) and sends nothing without a yes; the question names the server and says the statistics travel unencrypted. ARGUS_TELEMETRY_CONSENT=1 or 0 answers ahead for scripted runs."}
- {"area":"engine","text":"A warm terrain load reads its cells back from the disk cache on at most 8 threads (
PREFETCH_THREADS, now shared fromargus-platform) rather than one per core: on a many-core machine the reads waited on each other, and the cache read takes about half the time. The cells read are the same."} - {"area":"engine","text":"The terrain's far canopy (a layer with canopyM) now reads as a canopy and not a tiling of lit domes: crown sizes vary two to three times, groves, thin patches and clearings come from a large-scale noise, the lookup is warped so no grid shows, contrast is lower, and the crown relief settles sooner while the grove-scale tone stays at low contrast out to kilometres. Layers without canopyM are unchanged."}
- {"area":"engine","text":"The standard renderer's terrain chain is built faster on load. A cell's levels share their lattice vertices, so each vertex's normal and vertex colour (macro slope and cavity) is now read once per cell instead of once per level and again for the skirt. The meshes are the same bytes: a value is reused only for a vertex at exactly the same lattice position."}
- {"area":"engine","text":"
TerrainQuery::collider_heightgives the height of the ground a body touches: the heightfield collider's triangle, not the bilinear patchheightreads. The critic'sterrain/road-buriednow probes it, andentity.align ground: trueover a terrain rests an entity on it, so both agree with what physics does on rough ground with coarse samples (they can differ from the bilinear height by a quarter of a quad's twist)."} - {"area":"engine","text":"A terrain's far colour maps (one per cell, built on the standard renderer's load) are cheaper to build. Each quad of the layer map matches its corners' layers once instead of at every texel, the heaviest-layer picks use selects instead of branches, the sRGB colour bytes come from a threshold table instead of
powf, and each layer's far roughness is worked out once. The maps are the same bytes: tests check the table against the formula for every float in [0, 1], the per-quad pick against the per-texel one bit for bit, and whole maps against the old code."} - {"area":"engine","text":"Terrain layers that use a real heightTexture now blend on a common height range, so a full-range scan no longer outbids a flatter layer; layers without a heightTexture are unchanged."}
- {"area":"engine","text":"In the standard renderer a terrain that asks for the horizon map (
horizon: true) is drawn by the native terrain surface, which carries the map, while every other terrain is drawn by the stock terrain family (faster to load). The native surface does not read a layer's packed ORM map; the look is otherwise the same."} - {"area":"engine","text":"A terrain's layer textures (colour, normal, height, roughness and ORM maps) are decoded together on the asset cache's worker threads before the layers are built, instead of one after another: the terrain load's
decodestage is shorter on a terrain with several textured layers. The textures are the same bytes."} - {"area":"engine","text":"A large terrain loads faster: the cell layer map no longer uploads a mip chain it never samples, and the far maps' mip chains are built on the far maps' own workers. The frames are unchanged."}
- {"area":"engine","text":"A terrain's mesh build is about a third faster on a large terrain (the alpine scene's, 64 cells, fell from about 135 ms to about 90 ms): the cells' inputs and render hashes are made on all cores, and a cell's propagated errors are made once instead of at every meshing of the triangle-cap search. The meshes are byte for byte the same."}
- {"area":"engine","text":"The standard renderer's terrain chain is meshed faster on load. A level capped to its share of the triangles (levels 2 and 3) searches for its bound by meshing the level several times; those tries now only count their triangles, and the bound the search settles on is meshed once for its vertices and indices. The meshes are the same bytes: the counting walk is the meshing walk, and what a cell's edges hold, which the cells agree on, comes before it."}
- {"area":"engine","text":"The standard renderer packs and uploads a terrain's cell meshes on all cores instead of one by one, so a scene with a large terrain loads faster (mesh registration on the alpine scene fell from about 130 ms to about 55 ms on llvmpipe). The meshes, their ids and the frames are unchanged."}
- {"area":"engine","text":"A scene with a terrain loads faster in the standard renderer: the terrain's shader starts building while the renderer opens, and its shader code is smaller and quicker to compile. The look is unchanged. A terrain's batched draws allocate wgpu's fixed 2 MiB indirect-draw validation buffers once per device, the same as any scene that already batches."}
- {"area":"engine","text":"The standard renderer registers a terrain's chain meshes faster on load: the meshes are checked on the upload threads instead of one after another before them, and the upload uses at most 8 threads (past about 6 the threads only wait on each other in the driver). On an RTX 3080 the alpine scene's 256 meshes register in about 46 ms instead of about 60. A batch with a bad mesh still answers the first bad item's error and registers nothing."}
- {"area":"engine","text":"A terrain's rock detail now spends its triangle budget on the rockiest, steepest edges first (ties spread evenly by place) instead of coarsening the whole cell until nothing is split, so cells that are mostly cliff get their walls refined (on a large alpine test terrain at the default budget, the rock triangles added rose from about 66 thousand to about 188 thousand). Rock cells that used to be coarsened now change; terrains without
surface.rockDetail, and cells whose whole refinement already fit the budget, are byte for byte the same."} - {"area":"engine","text":"With
surface.rockBedspresent, cracks and recesses of the rock detail darken: where the displaced rock surface sits back (chips, runnels and the underside of a band's lip), the terrain's cavity colour darkens byrockBeds.crackDarken(default 0.6, up to about a third darker), so ledges and grooves read as depth under any light. WithoutrockBedsnothing changes: arockDetailterrain's vertex colours are byte-identical to before."} - {"area":"engine","text":"rockDetail look change: runnels no longer a fixed-pitch comb. The vertical grooves on rock faces now vary their pitch (0.6 to 1.4 of the old), depth (0.5 to 1.5) and track by place instead of repeating every 2.9 m (a 30 m noise warps the track by 4 m and a 35 m noise sets pitch and depth), and the strata ledges' rise is at least one mesh spacing (
maxEdgeM) tall, capped at half a band, so no row of identical drip spikes hangs under them. Only terrains with surface.rockDetail change; terrains without it are byte-identical, and the rockDetail pattern and mesh golden hashes were re-recorded."} - {"area":"engine","text":"Very rough terrain no longer costs extra triangles and video memory at the far levels of the standard renderer's terrain chain: the 1 m and 4 m levels are kept under a share of the full grid, with a slightly larger error bound where the ground is rough. Smooth terrain and the high-end renderer are unchanged."}
- {"area":"engine","text":"Terrain in the standard renderer now draws through the same shader system as every other material, and reads each layer's occlusion and metallic from its ORM map; its look is unchanged."}
- {"area":"engine","text":"Built-in broadleaf trees wear leafy twigs of small leaves instead of a few big flat leaves, with crossed twig cards so a crown reads as a volume close up; bark has finer flaking, stronger relief and lichen patches."}
- {"area":"engine","text":"On Linux, a finished scene load hands the memory its loading threads freed back to the system, so a loaded world's resident memory no longer stays at the load's peak. Nothing it uses is freed and nothing else changes; Windows and macOS are unaffected."}
- {"area":"engine","text":"Game text now draws in a proportional font by default: a project that ships no font of its own uses Inter (SIL Open Font License) instead of the monospace DejaVu Sans Mono, which stays as a fallback for Greek, Cyrillic and symbols. Exported games carry the font's licence beside it. A screen that relied on monospace alignment can copy the bundled JetBrains Mono into ui/fonts/ and name it."}
- {"area":"engine","text":"Boat bow spray, jet plumes and splash crowns are now particle effects (builtin water effects a game can replace), with ripples where the droplets land."}
- {"area":"engine","text":"Waterfall spray and mist are now a particle effect (a built-in a game can replace) instead of a separate render pass."}
- {"area":"engine","text":"Hiding an entity now hides everything under it in the hierarchy; showing it again brings back the children that were visible."}
- {"area":"engine","text":"
entity.visible = falseon an entity with no mesh or sprite of its own (an empty parent, a group) now hides its whole subtree, as it does on any other entity, andtrueshows it again with each child's own flag kept; readingvisiblegives back the flag. Before, the call did nothing and warnedscript-call-inapplicable; that warning is now only for an entity with no mesh, sprite or children."} - {"area":"engine","text":"Wakes are now raised waves in the water (the V of diverging crests, with transverse waves at low speed) with broken, lacy foam that thins as it ages, and spray is thin streaks of droplets: sheets off a fast bow, a rooster tail behind a jet, a crown of droplets from a splash."}
- {"area":"engine","text":"The waterline across the lens (a camera at the surface) is now one sharp, anti-aliased edge that follows the waves, with a thin dark line under it and a bright refractive lip above, instead of a dithered smear, the water just under the line is silvered like the underside of the surface, and the scene seen through it wobbles and softens slightly. A camera that has just come up out of the water gets drops on its lens that run off over a few seconds."}
- {"area":"engine","text":"Boats and jet skis turn more like real ones: the hull resists yawing, the yaw rate is capped (lower at low speed) and the steering lock eases off at speed, so a jet ski no longer spins in place. New water settings let a hull lean into turns and lift its bow as it climbs onto the plane."}
- {"area":"engine","text":"In the browser, the work budget now also counts arrow functions with an expression body (x => f(x)) and code inside a template's ${...}, so a runaway made only of those is stopped too; a heavy but legitimate callback that runs close to the 1,000,000 budget can be suspended slightly sooner than before."}
- {"area":"engine","text":"The browser build now runs physics with the same deterministic maths as the shipped native engine, so a browser and a native player step the same world bit for bit (about 12 KB more download)."}
- {"area":"engine","text":"The web runtime is smaller: the sea's ahead-of-time worker and the entity tag index are left out of it (the web has no threads to compute the sea on, and nothing there asks for entities by tag), and the built-in UI component manifest is embedded without its whitespace. Web games behave exactly as before."}
- {"area":"engine","text":"- The workspace service refuses a request from another site's web page (
Originother than its own:403 origin-rejected) and a POST body that is notContent-Type: application/json(415 unsupported-media-type), as the editor's control endpoint andargus run --servedo.POST /v1/evidencestill takes raw bytes. The editor,argus-agentand the CLI send what the rule wants and are answered as before."} - {"area":"agent","text":"Contributors: the documents the agent server serves (
argus://docs/<slug>) and the agent pack carries are one list,docs/agent-docs.txt(<slug> <path>a line, slug order afterstartandagent), read by bothcrates/agentandscripts/docs, in place of a list in each. A malformed line fails the build. The slugs and paths served are unchanged, and the agent pack builds byte for byte as before; thedocumentsan unknown slug's error lists are now in the file's order."} - {"area":"agent","text":"Agent tools on a project with a large startup scene are several times faster on disk: a write no longer reads and parses the startup scene again to report the project's warnings, finding a scene no longer re-checks the whole project, and project.open checks it once. On a 108,000-entity town that is about 4 s less per write; the warnings reported are unchanged."}
- {"area":"agent","text":"When an export or authoring run needs a workspace service and none is running, the AI is now told to call editor.start (or open the project in the editor) instead of being pointed at a program that is not installed on your PATH."}
- {"area":"agent","text":"The agent's tool list is about 1,500 tokens smaller with every toolset on: shorter tool wording, and arguments many tools share (scene, save, image, page and the like) described once in the server's instructions instead of on every tool."}
- {"area":"agent","text":"Asset generation is now Beta: the shared asset library and concept and model generation are on by default and supported. Generating still only happens in a project that has opted in, under a spend cap or a person's approval. A project that still lists
asset-generationunderexperimentalgets a warning (remove it), not an error."} - {"area":"agent","text":"explain.api and explain.search answer about a quarter shorter: a member no longer repeats its owner's documentation, search hits drop their score and any title that only repeats the id, and both carry the knowledge pack's id without its engine digests. The benchmark now starts the lead agent with the default tool list and lets it turn toolsets on as it needs them."}
- {"area":"agent","text":"The asset library works with nothing set up: a machine without a shared library is local-only, and
infonow says which mode it is in (local-only,shared-readorshared-write), whether it is ready, and what is missing. A default search no longer fails when the shared library is set up wrongly or cannot be reached; it searches your cache and says why the shared library was skipped. A library that does not verify is still refused. New guide: docs/ASSET-LIBRARY.md."} - {"area":"agent","text":"Searching the shared asset library is about twice as fast once its index is on your machine (0.8 s instead of 1.5 s for one search at p95 on the company library), because the index's small files are now read side by side. A new script,
packages/assets/scripts/bench-library.ts, measures search and fetch times against any library without writing to it."} - {"area":"agent","text":"The melee-moveset recipe's animator now names its fighter's feet (LeftFoot, RightFoot), so the feel probes' foot-slide check reads the feet the recipe declares rather than finding them by name."}
- {"area":"agent","text":"A big generated town now tells your AI how to make it lighter. When parcels.subdivide writes more than 50 buildings piece by piece, its suggested next step is to run it again with instance: true, which draws the same town with far fewer objects."}
- {"area":"agent","text":"A named agent's own Play (play.start with agent) now counts as one of the machine's headless sessions, like critic.play and export.run engines: when the machine is saturated or its headless capacity is full, play.start answers busy and starts no engine. A Play whose engine dies is recorded interrupted and frees its place at once. The same agent's critic.play and export.run run in its Play's slot, so they are not refused next to it. The workspace service takes --max-headless-sessions N (or ARGUS_MAX_HEADLESS_SESSIONS) to raise that capacity, which is half the cores by default: a 24-core machine holds 12 headless sessions, so 12 agents' Plays beside the lead's editor need --max-headless-sessions 14. Fixed on the way: headless sessions started at the same instant (twelve agents' Plays, or several critic.play runs) were all admitted past the capacity, because the service counted before recording; it now admits them one at a time."}
- {"area":"agent","text":"The playtester now plans a run against its time budget: it says up front when a course looks longer than the budget, and stops between goals when the next one would not fit, reporting how many goals it played and what timeout would cover them all, instead of running out of time halfway to a goal."}
- {"area":"agent","text":"When you ask for rows of joined houses (parcels.subdivide fit.rows) and few or none form, the answer now says why (rows.refused, by reason), and fit.rows.squeeze lets a house be squeezed slightly so a row can form where the plots are a little narrow for whole house widths."}
- {"area":"api","text":"A character's land, jump, moving and idle events now reach only that character's own behaviours; a script that watches every character subscribes with ctx.events.on(name, handler, { every: true })."}
- {"area":"api","text":"A behaviour or a screen can import a JSON file of its project as a value typed from its contents, such as the bounds
argus minimap-bakewrites (import BOUNDS from \"../../ui/images/minimap.json\"), instead of copying its numbers. It already bundled natively and in a web export; both script type checks now sayresolveJsonModulethemselves, and tests hold the native bundle, the web export and the checks to it. The Make a kart race guide's HUD imports the bounds and finds the karts by their tags."} - {"area":"api","text":"Accounts: sign-up now asks testers to accept the Beta Tester Terms (beta draft of 20 October 2026, version beta-2026-10-20), shown with the new Privacy Notice at /legal/terms and /legal/privacy (contacts support@cadarn.ai and privacy@cadarn.ai, analytics opt-in, no website analytics or marketing cookies, logs kept up to 12 months). People who accepted the old Early Access Agreement are asked once at their next sign-in."}
- {"area":"api","text":"Invite emails are short, plain and personal so they reach the inbox: from a named person with Reply-To set (MAIL_SENDER, MAIL_REPLY_TO), one link to the invite page only (the launcher download stays on the account page), and a plain HTML twin of the text. The admin console has Copy invite link on every pending invite, for sending invites from your own email."}
- {"area":"api","text":"The Privacy Notice (version beta-2026-10-25) now says what we actually keep. When you download or sign in, we record the country your connection comes from, not your IP address: our hosting provider works out the country, and we use the address only for a moment, to limit repeated attempts, and never store it. The Retention section gives each period: bug reports are deleted 12 months after they are closed; usage statistics are kept per person for up to 2 years, then only as anonymous weekly totals; access requests, and waitlist sign-ups that were declined or never invited, are deleted 12 months after their last change."}
- {"area":"api","text":"GET /events, /entities and /feel now refuse a query parameter they do not take (for example /events?name=), naming it and the allowed ones, instead of ignoring it and returning the unfiltered answer."}
- {"area":"launcher","text":"When the launcher updates itself, the installer it downloads is saved as
TalosLauncherSetup-<version>.msi, and a signed launcher or installer's \"More info\" link in its signature details goes to the Talos website. The update itself, and where it comes from, are unchanged."} - {"area":"launcher","text":"Installing a sample that is already installed now offers Open and Open folder instead of Try again, and the prompt to record an engine version in a project says what it does in plain words."}
- {"area":"launcher","text":"Open with AI shows the line for a scripted Claude Code run (
claude -p ... --allowedTools mcp__argus) with its own Copy button. The Connect guide now starts with the four steps (Open with AI, Connect, paste the line, approve), with the details after them. In Guides, the guide buttons stay in view while you scroll a guide, the guides no longer point at sections or files a new user does not have, and the bug-report guide says that attached logs also name your graphics card and driver."} - {"area":"launcher","text":"The Engine tab shows engine versions as tiles: version, channel, role, use and size, Launch, and a menu with Open folder, Verify, Repair, Set as default, documentation and Remove, plus an Add a version tile."}
- {"area":"launcher","text":"Opening a project pinned to an engine version that isn't installed now asks on the project's card. You can install that version (the project opens when it's in), open the project once with an installed version, or switch the project to one. Before, the launcher went to the Engine tab, whose banner didn't name the version and whose Install button could offer a different version."}
- {"area":"launcher","text":"The launcher says 'Not signed in' and 'once you sign in' instead of 'access token'; a pasted tester token is called a tester token, in Settings, My reports, Network activity, the CLI's --info (sign-in: ...) and the Start here guide."}
- {"area":"launcher","text":"Logs attached to a report from the launcher now show your project folders as <project>, not their real paths."}
- {"area":"launcher","text":"Signing in is the one way in, as in other engine hubs: until you sign in, the launcher shows only its sign-in screen. Press Sign in with your browser, sign in with the account your invite was sent to, and the launcher carries on by itself. There is no code to type and no token to paste. A tester token stored by an older launcher keeps working; the offline installer's launcher still takes one. Needs the accounts server with the browser sign-in (launcher_handoffs)."}
- {"area":"launcher","text":"The launcher updates itself: when its check at start finds a newer launcher, it downloads and installs it without a press, closes, and opens the new one. Editors you have open keep running. Turn off \"Check for updates when the launcher starts\" in Settings to update by hand instead (Engine page, Download, then Restart and update)."}
- {"area":"launcher","text":"The launcher has a left menu: Library (Projects, Samples), Engine, Learn (Start here, What's new) and Settings. New project is a clear button on the Projects page, and the first-run Engine page says how big the download is."}
- {"area":"launcher","text":"Start here is now a short guided page of five steps (install the engine, open a sample or make a project, connect your AI, play, export) that shows what you have already done, with a Close button and a Full guide. It no longer closes when you press a tab."}
- {"area":"launcher","text":"The launcher sends your sign-in or tester token only to Cadarn's own download host; a custom update source (a mirror) is sent no token at all."}
- {"area":"launcher","text":"Release builds carry no path of the machine that built them: the editor's and agent's fallbacks to the source checkout are development builds' only, and the Linux and Windows release builds remap the checkout, cargo's home and the target folder (--remap-path-prefix; -ffile-prefix-map for C on Linux). linux-tar.sh and build-engine.sh refuse a binary that still names them, so an install tested on the build machine cannot pass by reading its checkout."}
- {"area":"launcher","text":"Request a feature opens the report form with Feature request chosen, instead of a web page."}
- {"area":"launcher","text":"The Connect guide says to expect ten or so approvals for a first AI change, and the Share guide covers the \"Unknown Publisher\" warning. On a managed install a report now gets the same confirmation as from the editor: reference, contents, where it is and the address to send it to."}
- {"area":"launcher","text":"The Samples page reads the samples list again when you come back to it, so a new sample shows without restarting the launcher. A project's card names the exact engine version it opens with, such as Talos 0.6.1, and follows an update or a rollback."}
- {"area":"launcher","text":"The engine's private Node ships zstd-compressed, as esbuild does: an install is about 79 MB smaller on Linux and 53 MB on Windows (166 MB to 112 MB) (the Linux download grows about 2.7 MB). The first tool that runs Node (the agent's critic, a TypeScript check, the asset tools) unpacks it into the user's cache once (the first critic check took 0.7 s on Linux, 2.3 s on Windows); ARGUS_NODE still names another Node."}
- {"area":"launcher","text":"The installed-size baselines move up, with Sean's OK for the 0.7.0 friends build: Windows to 173.86 MB and Linux to 197.73 MB, from 167.8 and 192.3. The growth is features (the fantasy-town building kit, +1.3 MB, and engine code since 8 October), not waste. Both stay far under the 250 MB cap. Packing the SDK's Node next week takes them down by about 61 MB (Windows) and 76 MB (Linux)."}
- {"area":"launcher","text":"The per-user tool cache keeps the 8 most recently used unpacked tools (was 4, shared with engines' count), so esbuild and a packed Node of four installed engine versions stay side by side; the SDK reader accepts a packed Node (not shipped packed yet)."}
- {"area":"docs","text":"Contributors: the agent pack's search checks can live one file per topic in
scripts/agent-pack/tests/asked/*.json(format in its README), besidestart.test.mjs's own list, so branches that each add searches no longer conflict on the same lines. A search asked twice fails the run."} - {"area":"docs","text":"The docs site is smaller: the sidebar's area list is drawn by script from nav.json instead of repeated in every page (a reader without script gets one link to the docs home), and very short pages (a type alias, a constant) are sections of their area's index page, so their old page URLs no longer exist; links, search and llms.txt point at the section. Rule, runtime and project codes keep their own pages. Pages under docs/latest/ are small redirects to the newest series rather than a second full copy; deep links still work, but the Markdown twins and data files exist only under the series folder, and the docs llms.txt links the series folder directly."}
- {"area":"docs","text":"The third-person character recipe now shows how to use your own character with walk, jog and sprint clips played by speed: setting its forward, reading each clip's own pace, and the blend tree to write."}
- {"area":"docs","text":"START-HERE and INSTALL.md say how your AI plays on a machine with no display: the agent starts the project without the editor's window, so a headless AI can Play"}
- {"area":"docs","text":"Friends' docs agree with each other: the friends guide points Linux users to START-HERE's On Linux instead of saying Linux isn't supported, the editor's menu is quoted as Help ▸ Report a bug…, and a Linux snag no longer repeats an install line"}
- {"area":"docs","text":"Learn > Guides has a new Playtest and aim with the mouse guide: how your AI play-tests a game, aiming with the mouse in scripts, and the Inter default font."}
- {"area":"docs","text":"The friends' guide starts with Kart Starter: drive it, change one vehicle setting in Details, Play again; it lists every sample and says how to connect an AI assistant."}
- {"area":"docs","text":"Known issues for testers: six problems fixed in this build are gone (terrain paint layers, Play after sleep, Twin Trail's Escape, the kart's reset speed and lost keys, the editor closing on a driver reset); sign-in, bug reports, vehicle assists, warnings from your AI's checks and other known problems are listed, each with a way round it"}
- {"area":"docs","text":"START-HERE's Linux section says to keep the engine folder whole (the editor starts the workspace service and builds with the SDK from its own folder), and lists the top three Linux snags with what to do: no workspace service or SDK found, no display or missing X11 libraries, and a project on a Windows drive"}
- {"area":"docs","text":"The roadmap now takes its Stable, Beta and Experimental labels from the engine's feature list and shows each package with its parts. A check fails if the two disagree, and \"First version\" now reads \"Beta\"."}
- {"area":"docs","text":"The agent guide's playtester section now says how mouse-bound actions are clicked (at each thing on screen and a grid, with off-screen targets brought into view first) and that a settings button that only changes a volume or a mute counts as working."}
- {"area":"docs","text":"The agent guide now documents critic.play's kind argument: what each driver does, how auto picks between walking the goals, exploring the actions and walking the menus, the simulated time budget and when a run stops for it, and the codes these runs give (nothing-to-drive, no-response, dead-button, menu-dead-end, over-budget, untested-flows)."}
- {"area":"docs","text":"The build now checks the asset files of prefabs that scripts spawn, naming where it looked (a prefab's paths resolve from the scene's folder, not the project root) and any file of that name at the project root; the agent guide says so."}
- {"area":"docs","text":"The roadmap lists three features as arriving in the next release: the animation graph view, prefabs inside prefabs, and a good default look."}
- {"area":"docs","text":"The agent guide now states the 0.001 to 1000 entity scale limit up front, with how to build a ground wider than a kilometre."}
- {"area":"docs","text":"Start here is written for someone trying Talos on their own: it opens with what Talos is and is not, says no AI is needed (Claude Code is optional and paid), drops the wording that assumed a friend had sent the installer, says Talos is Windows-only for now, and lists the Kart starter as the template for a first hour, with a short drive-change-export walk through it."}
- {"area":"docs","text":"The agent guide now says how the terrain collider differs from the surface the tools read: each quad of the heightfield is two flat triangles (split from its (x0, z1) corner to its (x1, z0) corner), while the tools read the bilinear patch, so a hand-made clearance over the terrain needs a quarter of the quad's twist on top. It also says how a road's conform already allows for the triangles at its edges."}
fixed
- {"area":"editor","text":"After a normal close, the next open no longer lists 'change … abandoned: the human let go' in Activity: the editor letting go of what you had selected is bookkeeping (shown under the Service filter), not a lost change."}
- {"area":"editor","text":"An agent's editor can Play again with the workspace service keeping track. Before, the editor's own scene preview used up the agent's one session, so the service turned down every Play that editor started: Play still ran, but unrecorded, and the Output log repeated a \"423 busy\" warning every five seconds."}
- {"area":"editor","text":"An editor started with --agent-owned shows the scene as soon as it opens, also with the high-definition renderer: the view no longer stays dark until Play while the slow first frame (the HD warm-up) held every later picture back, and the view is drawn on the frame the window or a panel resizes it."}
- {"area":"editor","text":"After you Save with the workspace service running, a crash no longer loses the edits made since: the recovery copy is offered back and restores."}
- {"area":"editor","text":"The Add behaviour list scrolls instead of growing, so New behaviour… stays on the Details panel at 150 % however many behaviours there are."}
- {"area":"editor","text":"When you first open a new 2D project, the Getting started card no longer covers the right of your level. The view zooms out and moves once, so what the game's camera shows sits beside the card. After that the view is yours, and closing or reopening the card doesn't move it."}
- {"area":"editor","text":"Pressing F on a child entity (a particle emitter under a vehicle, say) now frames where it is in the world instead of its offset inside its parent; the Presentation view's camera entity and scene framing use world positions too."}
- {"area":"editor","text":"An import the editor refuses through its control endpoint (
POST /v1/events) now answersimport-refusedwith the importer's own reason, instead ofcontrol-missedand advice about opening menus."} - {"area":"editor","text":"In a 2D project Create > Building and Street are greyed with the reason (they make 3D houses a 2D game does not show), instead of failing with a scene error or adding a street you could not see."}
- {"area":"editor","text":"Create ▸ Building and Create ▸ Street now work with kits that give pieces wear variants (such as roof colours). Each wear material is added to the scene and copied into the project with its textures, as the assistant's building tool already did. Before, the editor refused such a kit."}
- {"area":"editor","text":"Create > Street made beside a house no longer lands off the edge of the floor: when you look at the ground, the street goes to the nearest clear spot with ground under all of it."}
- {"area":"editor","text":"The Outliner and Details column keeps its width when you select things: labels are no longer cut off on the left and the viewport no longer jumps in size. Long numbers in a field are trimmed to fit rather than pushing the panel wider."}
- {"area":"editor","text":"Details: resting on a row's label shows its whole name and what the field is, in the contract's words (a long label is cut to its column)."}
- {"area":"editor","text":"Edit ▸ Paste is greyed when the clipboard holds no copied entities, and says to Copy or Cut one first. Edit ▸ Undo and Redo name the step, for example \"Undo Move Crate\", and the toolbar's Undo and Redo tooltips use the same name. The Edit menu now has Unhide All, Isolate Selected (End Isolate while one is on), Lock / Unlock, Drop to Floor and Clear Selection, each with its shortcut and, when greyed, the reason. Editor Preferences ▸ Keyboard Shortcuts shows every action's whole name, wrapped instead of cut off, and on hover says where the key works (while editing, while flying the camera, or while Play runs) instead of an internal id."}
- {"area":"editor","text":"The Activity feed now says what happened in plain words (\"Starting preview…\", \"Preview running\"); session ids and the service's bookkeeping moved to a Service tab and to each row's details. Play no longer reports \"1 update pending\" right after opening a new project when nothing has changed."}
- {"area":"editor","text":"An editor that closes unexpectedly no longer loses the edit you just made: the recovery copy is written two seconds after you stop editing (it used to wait a minute), so the next open offers it back. Reopening also no longer shows a red 'lease-held' conflict against your own earlier session."}
- {"area":"editor","text":"Exports made from the editor or by an agent now carry the project's selftest/*.json scenarios, release and development alike, so the shipped game runs them with --self-test <name>; a scenario file that is not JSON or has no selfTest version is refused by name."}
- {"area":"editor","text":"A project opened for the first time now starts with the camera above and behind your player, or looking at your scene's content, instead of at ground level on the origin."}
- {"area":"editor","text":"The editor's start phases (the \"startup\" state its control endpoint reports) now mark firstFrame when the first frame is on screen rather than when it was built, so a slow first start, such as the graphics driver compiling shaders, shows in firstFrame instead of being hidden."}
- {"area":"editor","text":"The editor no longer crashes at start when the graphics driver loses its device as the window opens (seen with Vulkan on an NVIDIA RTX 3080, driver 610.62, as \"Out of memory\"). It now tries the next graphics API instead, Vulkan then DirectX 12 on Windows, and says so in one log line. When no API is left it exits with the reason rather than a crash. Games built with the engine open their window the same way and get the same fallback."}
- {"area":"editor","text":"An editor window that nobody is using no longer redraws itself 15 to 40 times a second: it draws when something changes (input, Play, an agent's change, a job's progress) and twice a second otherwise. Idle CPU fell from 1.7 cores to about 0.2 on a machine without a GPU; working in the editor feels the same."}
- {"area":"editor","text":"Importing a building kit's piece (a model its kit.json lists, such as the engine's own fantasy-town kit) now opens the Import window at the kit's unit and says so, instead of arriving a third of its size."}
- {"area":"editor","text":"On Windows with Node 24 the Library, Generate and API Keys panels could not start the asset library tool and showed only an exit code; they now start it, and when the tool fails the panel shows its full error output. Searching the library with words and the project style no longer lists assets that only match the style."}
- {"area":"editor","text":"Dialogs now fit the window: in a small or scaled window the body scrolls and the title and buttons stay on screen, and the Export dialog scrolls its result into view when an export finishes."}
- {"area":"editor","text":"Started where there is no display (a Linux machine without a desktop session, or WSL with WSLg not running), the editor now says in plain words that it could not open its window, what the display variables are set to, and what it needs, instead of a windowing library's error with a source path."}
- {"area":"editor","text":"The Output Log shows one line per Play and one per Stop; session ids, ports, frames and service details are Verbose (still in the log file). The missing-SDK warning says what to do, and the Play badge reads \"editing preview\" with a plain explanation instead of a warning-coloured \"unverified content\"."}
- {"area":"editor","text":"After Send in the editor's Report a bug, the confirmation also says where the report is kept once the launcher has sent it, and a report from the editor lists the launcher's version as \"not known\" instead of 0.0.0."}
- {"area":"editor","text":"Saving a large behaviour script while the game runs no longer stalls the editor: it is compiled in the background and swapped in between two ticks once ready (a newer save replaces one still compiling; Stop drops it)."}
- {"area":"editor","text":"Two editor tests (the idle frame gate and the export panel's short-window scroll) wait for egui's animations in wall time instead of counting frames, so they pass on a fast Windows GPU as on Linux. The editor itself is unchanged."}
- {"area":"editor","text":"A road no longer vanishes from the editing view (or from a Play being edited from the free camera) after an edit to anything else, such as a particle rate in Details; its surface, barriers and gates stay drawn through edits, moves and undo."}
- {"area":"editor","text":"An export now asks the engine it packs whether it serves the query API (its --info) instead of searching its bytes for the release engine's message, which a serving engine can carry too; an engine that cannot answer is still read by its bytes."}
- {"area":"editor","text":"Export: a successful export lists the Beta and Experimental parts the game uses as a neutral note, not an amber warning; a part not opted into is still a warning"}
- {"area":"editor","text":"An export no longer ships an engine left in the target folder by an older checkout. The cached deploy engine and the shader tool carry a stamp of the engine source they were built from; a mismatch is rebuilt, or refused as
engine-stalewhen building is off."} - {"area":"editor","text":"Exporting right after a save no longer warns that an edit is still settling and missing from the export: the editor's hold on what you have selected no longer counts as an edit in progress."}
- {"area":"editor","text":"Clearer first-run messages: File menu hovers, submenu arrows, Keyboard Shortcuts, the launcher's empty list, the 2D template, and the refusals for a non-project folder, a taken name, a read-only save and a stale build each say what happened and what to do."}
- {"area":"editor","text":"Help > Documentation opens the documentation for this version, and Copy documentation location copies a full address or path instead of a relative one."}
- {"area":"editor","text":"A new project no longer shows a red No service chip or a warning while the workspace service is starting or turned off, and the bundled Collection course no longer logs a UI style failure when played."}
- {"area":"editor","text":"The Getting started card now says what Play will be like for the scene you have open. On a first-person scene it says Play puts you in the player's view, the mouse looks round and the game's keys move you. On a third-person scene it says the camera follows the player. The W/A/S/D line now says it flies the editor camera, so it isn't mistaken for the game's controls."}
- {"area":"editor","text":"With View ▸ Show ▸ Game UI on, the viewport's top-left view menus and scene line fade, so a game's HUD under them can be read (the Collection course's \"Collect cube 1 of 5\"). They come back in full when the pointer moves onto them. The scene line fades the same way during Play, where it covered the Kart Starter's \"Lap 1\"."}
- {"area":"editor","text":"The gizmo toolbar's snap values (grid, angle and scale) now say what they are when you hover them, and that clicking picks another step. A greyed Align says it needs Surface snapping turned on first. The Angle and Scale snap toggles' tooltips are plainer, too."}
- {"area":"editor","text":"An imported character now moves: Import gives a model that has animation clips an animator (one looping state per clip, starting on its idle clip), so it plays when you press Play and its clips show in Details for preview. Details ▸ Add component also offers Animator for a model with clips."}
- {"area":"editor","text":"An imported character no longer walks backwards: when a model faces glTF's usual +Z front, Import now sets its forward for you instead of only warning about it."}
- {"area":"editor","text":"An import that is refused for a missing or separate picture names the file as it is named (\"Holz ä 木.png\"), not as the model file encodes it (\"Holz%20ä%20木.png\")."}
- {"area":"editor","text":"Import now takes a .gltf whose geometry and textures are separate files beside it (the way most free character and animation packs ship): it packs them into one .glb in your project instead of asking you to re-export. Your original files are not changed."}
- {"area":"editor","text":"After importing a .gltf with its files beside it, the status line says what landed in the project (\"Imported tri.gltf as tri.glb\"), not only the .gltf that was dropped."}
- {"area":"editor","text":"A model with a texture that is not a readable PNG or JPEG (another format under a
.pngname, a download cut short) is refused at import, naming the material and the picture and saying to save it again, instead of importing and then never appearing. A file that is not a model at all (a saved web page, a zip, an empty download) says what it looks like instead of \"expected value at line 1 column 1\". A texture file named in capitals (WALL.PNG) beside a.gltfloads."} - {"area":"editor","text":"A greyed-out menu item now says why when you hover it. With nothing selected, Cut, Copy, Duplicate, Delete, Rename, Frame Selected and Hide say to select something first. File ▸ Save says there is nothing to save, and Edit ▸ Undo and Redo say there is nothing to undo or redo. During Play, each says to stop Play first."}
- {"area":"editor","text":"More menu items now say what they do when you hover them: View ▸ Preview effects and Presentation view, Help ▸ Viewport controls, Help ▸ Report a bug (a form you review first, and nothing is sent until you press Send), and Help ▸ Request a feature (it opens a web page). A greyed File ▸ Set as startup scene says the scene already is the startup scene. The Window menu's tooltip now lists every window, including Library, Profiler and Animator."}
- {"area":"editor","text":"A model, material, texture, sound, effect or sprite picture that does not load is now a warning in the editor's Output Log, naming the asset, its file and what stands in for it. Before, it showed only on the terminal, and a missing model was a cube with no explanation."}
- {"area":"editor","text":"Create ▸ Road moves the view to show the new road, as Focus does. It used to be made out of sight, so in the Kart Starter the button seemed to do nothing."}
- {"area":"editor","text":"Opening a project last saved by a newer engine series now warns in the Output Log, naming both versions. Before, it opened without a word."}
- {"area":"editor","text":"When the editor can't start your graphics card, it now says so in plain words: update your graphics driver (Vulkan, or DirectX 12 on Windows), then start it again. On Windows a message box shows this, with what the driver said and where the log is. Before, a double-clicked editor just closed without a word."}
- {"area":"editor","text":"A game exported from the editor now includes its terrain files and the terrain's layer materials, so the exported game has its ground."}
- {"area":"editor","text":"In a new 3D project (Empty or Starter), the floor is solid where it is drawn: before, its collider sat 12 cm lower, so a player or a kart sank into the floor."}
- {"area":"editor","text":"Typing a six-digit colour into a colour field now keeps every digit (it used to stop at three, so \"#ff0000\" became yellow). A new terrain no longer flickers against a starter's floor, and a new foliage layer paints enough plants to see. In the launcher, a name field selects its text when clicked, and a plain \"Opened ...\" line clears when you move to another screen."}
- {"area":"editor","text":"Importing a picture (PNG, JPEG and the like) now says that Import takes 3D models and that textures come in with the model, instead of showing a file-format error."}
- {"area":"editor","text":"During Play the scene line (file, Play, paused, speed, unsaved) sits in the top-right strip beside the speed and Eject, so it no longer covers the first line of a game's HUD."}
- {"area":"editor","text":"The status bar no longer says Play is up to date while Play is running edits that are not saved. It now says Play runs unsaved edits, before and during the run."}
- {"area":"editor","text":"One click on Stop stops Play. Play clicked on the toolbar no longer locks the cursor where it is (on Windows that pinned it on the Play button, so the first click on Stop was lost); the game gets the keys at once and the mouse after a click on the game image. A line under the game image says which (\"Click the game to give it the mouse\" / \"Shift+F1 gives the mouse back\") and names the stop key, and Shift+F1 (
play.release-mouse) gives the mouse back without stopping, as in the usual editor."} - {"area":"editor","text":"Play keeps working when the computer's clock steps back (a time sync, waking from sleep). Before, a step during Play left Play refused as busy, or with no renderer, until the editor restarted."}
- {"area":"editor","text":"Play's tooltip and Start Here no longer say Play asks you to save first. Play runs the scene as it is, unsaved edits included, and saves nothing."}
- {"area":"editor","text":"Play on unsaved edits says so once in the status bar, not twice."}
- {"area":"editor","text":"While you edit a prefab, the viewport label and the Outliner header name the prefab file instead of the scene, and the bar over the viewport reads the nesting path with the instance count together, for example Scene > Car > Wheel · 2 instances in 1 prefab."}
- {"area":"editor","text":"The Presentation view's orbit turns smoothly: it used to move only twice a second once the exit hint had faded, and about once a second in an editor started for an agent (
--agent-owned)."} - {"area":"editor","text":"The Presentation view has an Exit presentation (Esc) button that fades when the mouse is still, and Escape leaves it. Changing the view (Top, Front, Side, Perspective) now works while it is on instead of snapping back."}
- {"area":"editor","text":"Opening a project in a folder the editor cannot write to no longer makes every frame fail. The editor warns once in the Output Log that it can't write there, so it won't remember the view and selection, and saving the scene will fail until the folder is writable. It carries on working."}
- {"area":"editor","text":"Moving or renaming a file no longer crashes the editor when a script or style file in the project contains non-English characters before a url()."}
- {"area":"editor","text":"A bug report sent from the editor with logs attached no longer names where your project folder is (it reads
<project>, as the launcher's already did). Sending saved reports from the command line now lists each one by the reference its confirmation shows and says where it went."} - {"area":"editor","text":"While a road's points are being edited, Details explains how: drag a point to move it, Ctrl+click the ground to add one, and Delete to remove the picked one. It also says that a click anywhere else selects what is there and ends editing. Before, this was only in the Edit points button's tooltip."}
- {"area":"editor","text":"With the workspace service running, Save no longer silently drops an outside edit: if the scene file was changed outside the editor and that change touched an object you also changed, Save asks (Overwrite, Reload or Cancel) like it does without the service. Changes a tool or script landed through the service, and outside edits to other objects, never ask."}
- {"area":"editor","text":"An edit made to the open scene file outside the editor (a text editor or an AI tool) now shows up: a scene with no unsaved edits reloads by itself, and one with unsaved edits asks whether to Reload or Keep mine."}
- {"area":"editor","text":"A scene's script module that reaches another folder of the project with
..(for example../behaviors/x) now plays and exports the same way it builds, instead of Play wrongly reporting that the build output was collected; a module path that leaves the project is refused by name."} - {"area":"editor","text":"A syntax error in a plain JavaScript (
.js) behaviour no longer stops the project opening either, and the Output Log gives its line as well as its file. When a behaviour has a syntax error, its entity starts without that behaviour wherever the scene loads: the editor, a preview that isn't a checked build, and a bareargus run. Each one is reported as a script error naming the file and line, so you can find and fix it."} - {"area":"editor","text":"A syntax error in one of your behaviour scripts no longer stops the project opening. The project opens without that behaviour on its entity and loads the rest as usual. The Output Log shows one error naming the file, the line and what is wrong (esbuild's message, without Node's stack trace or the esbuild command line)."}
- {"area":"editor","text":"Closing the editor normally no longer makes the next open say that the previous workspace service did not stop cleanly: the editor now asks the service to stop, instead of ending it (on Windows it always ended it)."}
- {"area":"editor","text":"A custom-shader material with alphaCutoff no longer gets a false 'alphaCutoff does nothing' warning; a blend: mask shader uses it."}
- {"area":"editor","text":"A new project from the 3D Starter now has a player to play: press Play, then WASD walks a capsule character and the camera follows it. Before, the Starter had only a spawn point, so Play showed a still picture."}
- {"area":"editor","text":"With no workspace service, the status bar no longer shows a cut-off \"No workspace ser…\" beside \"Local only\", which said the same thing. It now says \"Builds not checked\", with the full reason on hover. The \"Content art_…\" id is shown only once a workspace service is connected; before that it meant nothing on a brand-new project."}
- {"area":"editor","text":"A new 3D project's scene now has room for a game: its budgets were placeholders (1000 triangles, 10 draw calls), so the first model you added made the critic fail with over-budget errors, and a walking player was stopped 30 m from the centre. Now 2 million triangles, 2000 draw calls, 512 MB of textures, 64 moving bodies, in a 500 m box."}
- {"area":"editor","text":"Terrain ▸ Add layer no longer offers materials that only moving things use. In the Kart Starter it listed the kart's paint, seat and tyres next to grass. A material that something standing still uses as well is still offered."}
- {"area":"editor","text":"A terrain layer whose
materialis a scene material asset's id (which the contract allows) now plays and exports: Play no longer refuses with a missing file named after the id (.../grass). The Details panel's swatch for such a layer shows the asset's colour instead of grey."} - {"area":"editor","text":"The \"A script threw an error\" toast now starts with the file and line, relative to the project (for example
scenes/behaviors/drift.js:3). It no longer shows your project's full folder path, and a long message is cut between words rather than in the middle of one."} - {"area":"editor","text":"Unpacking a prefab one level no longer copies the assets of the prefabs nested in it into the scene; only the unpacked prefab's own assets are added, and Unpack Completely still adds every level's."}
- {"area":"editor","text":"After Unpack Prefab, a part you had hidden or locked in the Outliner stays hidden or locked under its new id, and again after Undo."}
- {"area":"editor","text":"Details: a vehicle's gears and torque curve are one field per number (rpm and N·m named over the curve's points), with × per item and + Add, which carries the list on, instead of JSON text"}
- {"area":"editor","text":"During Play, the status bar says how many behaviours were stopped by errors, as a warning, instead of \"Play is up to date\". In Details, a component whose model or file is missing says \"(missing asset)\" on its header, folded or not, and its tooltip names the file. The Getting started card lists Play before Add a component, and it no longer offers documentation in a build that has none."}
- {"area":"editor","text":"A typo in a behaviour that several entities use is one line in the Output Log, ending with how many more entities use it, instead of one identical line per entity. Open by path on a folder that is not a project no longer ends with an internal code. The New project page says a taken name in one short line, without repeating the path shown under the fields."}
- {"area":"editor","text":"Export > Web finds the engine CLI only in the installed engine or the editor's own checkout, never in the project or a folder above it, so a
packages/cli/bin/engine.jsinside a project is never run."} - {"area":"editor","text":"On Windows the asset library could not find the quality gate it needs (it looked for the program without its .exe), so searching, importing, rating and re-checking library assets failed."}
- {"area":"editor","text":"On Windows a build tool the workspace service started (such as esbuild) could be left running, stopped and holding the service's output open, when the service or the editor quit at the wrong moment. Build tools now always end with the process that started them."}
- {"area":"editor","text":"On Windows, opening a project could fail with \"Access is denied\" while antivirus or the search indexer briefly held a file the workspace service had just written; the service now retries, as it already did for its other files."}
- {"area":"engine","text":"A 2D project set to the HD renderer (or run with
--render hd) now draws with the standard renderer and says so (project-kind-2d-hd). HD has no orthographic camera, so it drew such a game as an empty sky; 2D games are meant for the standard renderer, which draws them in about 0.1 ms of GPU time."} - {"area":"engine","text":"A crossfade or a partly weighted animation layer no longer snaps a joint round by half a turn in one frame when the two poses pass 180 degrees apart; the blend keeps the arc it started on."}
- {"area":"engine","text":"An animator whose transitions nothing can fire now says so when the scene loads (animator-transition-unheard), naming the events and the line to add: a transition's \"on\" is heard by the built-in animator behaviour, which the door example in the docs left out, so the example loaded and stood shut. Importing a four-legged animal such as the Khronos fox no longer tells you it lies on its side; it stands, and its head tells the import which way it faces. ctx.animator.bone returns null for a bone the rig does not have, as documented, rather than undefined."}
- {"area":"engine","text":"A single long animation step that carried the playhead over a clip's loop point several times could fire a looping clip's events one time too few; root motion from a state being crossfaded out now keeps moving the character during the fade instead of stopping on the first tick."}
- {"area":"engine","text":"animator-window-unreachable now counts blendOut in world seconds at the state's playback speed, matching the real hand-back; a snapshot restore puts a controller's walk speed back to the authored one."}
- {"area":"engine","text":"An animation layer at weight 0 (or under 5%) no longer fires events or opens windows, so an invisible swing cannot hit; changing a layer's weight now fades at the layer's blend-in and blend-out rates instead of jumping."}
- {"area":"engine","text":"A layer mask's per-bone weight on a bone below one weighted 0 now applies, as documented; the error for playing on a layer that was left out because its mask names an unknown bone now says so."}
- {"area":"engine","text":"Putting a snapshot back no longer counts as an animation pop: a character's pose jumping to the restored moment was reported as a one-tick pose jump, so the playtester flagged a pop on walking characters it explored by restoring snapshots."}
- {"area":"engine","text":"Root motion now takes only a clip's travel along the ground and leaves the hips' height in the pose: a roll or a lunge that dips no longer plays in mid-air on a character controller, and an animated entity without a controller no longer rises and sinks through the floor."}
- {"area":"engine","text":"An animation window no longer opens on a state that is being crossfaded away: an attack cancelled into a roll before its hit frame no longer hits during the roll, and a window that was open ends on the first tick of the crossfade. A one-shot handing over at its own end still opens windows on its last frames."}
- {"area":"engine","text":"Foot IK and root motion now honour a model's import transform (its forward axis and unit scale), so a model declared to face +Z or imported in centimetres no longer solves its feet against a mirrored or mis-scaled body or travels the wrong distance."}
- {"area":"engine","text":"A snapshot now holds each animator's full gameplay state: a one-shot attack in flight, its hit window, a hit-stop and the root motion due next tick. A world restored mid-attack, or a late joiner, now carries on exactly as the original run. Before, a restore kept only the state name and time, so the attack moved differently on the next tick. Snapshots also show the one-shot, layers, speed and open windows for a reader. An older snapshot still restores by state and time."}
- {"area":"engine","text":"Arabic UI text now draws every letter of the Arabic block: the bundled Arabic font was cut from one sentence, so letters such as أ ئ ث ش غ, the tanwin mark and the Arabic decimal and thousands separators came out missing. The font now carries the whole block, its presentation forms and the joining rules."}
- {"area":"engine","text":"The asset gate's written model keeps only the vertices it draws: decimation rewrote just the index lists, so a gated LOD0 (and its levels, which share its vertices) still carried every vertex of the source mesh (a 19,800-triangle sphere gated to 3,000 kept 10,201 vertices and drew 1,723). Shared, interleaved and 3-byte attributes are copied, and min and max are recomputed."}
- {"area":"engine","text":"One damaged font in a project's ui/fonts no longer stops Play: it is skipped with a ui.font.unusable warning naming the file, the build reports build.font-unusable, and the other fonts still draw."}
- {"area":"engine","text":"HD lakes under a tall bank or cliff no longer turn their reflection of it into bright sky where the reflected rays leave the top of the frame: the bank's mirror image carries on down the water and gives way to the water's own colour smoothly, with no step."}
- {"area":"engine","text":"HD rivers seen at a grazing angle (from a bridge, along a town river) no longer show black speckles: ripple faces turned away from the eye no longer mirror the dark walls and piers standing in the water."}
- {"area":"engine","text":"Under the sea the water is no longer near black looking away from the sun: the deep-blue grade keeps the light's brightness and the many-times-scattered light is added, brighter toward the surface."}
- {"area":"engine","text":"Far broadleaf trees (oak, birch) drawn as impostors are no longer about a quarter darker than the trees themselves when the sun is behind the camera: the impostor's surface no longer sinks into the crown's own shadow at a distance."}
- {"area":"engine","text":"Build Theatre frames a scene by the size of what is in it, not only where each entity's centre is, and leaves lights out: a starter whose floors and walls are centred on one line is no longer shot as a sliver from up close."}
- {"area":"engine","text":"theatre live keeps to the wall clock: a 30-second recording covers 30 seconds of the session, instead of a fast machine squeezing more of it into the clip."}
- {"area":"engine","text":"Convex built-ins (sphere, capsule, cylinder, cone) and other convex-hull colliders placed many times at random uniform sizes now share one shape per model instead of building one per body: 1M generic props load in 12 s and 8.2 GB instead of 74 s and 32.6 GB, and everything they collide with moves bit for bit as before."}
- {"area":"engine","text":"Two threads writing the same cache file at once (HD content and impostor caches, and the launcher unpacking a packed tool) no longer fail or leave a half-written file: each write now uses a temporary name of its own, and on Windows the final rename is retried when a virus scanner or indexer briefly holds the file."}
- {"area":"engine","text":"The canopy infill's ring mode no longer places trees on snow, bare rock, scree or river beds of a terrain (a ground without materials is unchanged; the ring itself is off by default and pay-for-use)."}
- {"area":"engine","text":"A ray or shape cast that meets two things at exactly the same distance (the seam between two floor tiles, a character touching two bodies) now names the same one on every machine, after a restore and in a world built in another order: the one whose scene id sorts first."}
- {"area":"engine","text":"Clearer command-line messages: at a terminal
argus runstarts with one readable line (title, scene, window) instead of a long JSON line, which tools still get through a pipe; a missing scene or a file that is not a scene says so in plain words; andargus-project validateat a terminal lists each problem and exits 1, refuses an option where the location goes, and suggests the right command for a typo."} - {"area":"engine","text":"-
onCollision,onCollisionStayand the\"collision\"bus event are heard only for bodies that are touching. A point the solver used to stop an approach a little short of the surface (within Rapier's 2 cm prediction distance) no longer starts a contact or keeps one going; it is still incontacts(),GET /contactsand the snapshot, with its impulse, for a vehicle's wall handling. Since triangle meshes and heightfields report the impulse the solver applied, such points under a kart's chassis bobbing over a road mesh, and at its seams, were heard as collisions every tick, and a kart game took them for walls and spun (#13214). A body the solver stops short of a surface is heard on the tick it touches, with that tick's impulse, which for an impact braked short can be less than the braking point carried; readGET /contactsfor the braking itself."} - {"area":"engine","text":"A component missing a required field now names the component and the field (the \"goal\" component is missing its required field \"id\"), and agents can read docs/VFX.md, presets included, as the vfx document."}
- {"area":"engine","text":"Characters stay on the ground walking up and down stairs, climb a riser exactly as tall as their step height, stop shaking when pushed into a wide corner, and no longer sink into or stall on a single very large floor box."}
- {"area":"engine","text":"Ground-cover clumps no longer read as planted rows: each clump centre is placed anywhere inside its cell (not the middle half) and each clump has its own radius, 0.5 to 1.5 times the layer's, so tufts vary in size and spacing. Layers without a clump are unchanged; the cover format version is now 2. Each blade now joins the nearest clump centre among the 3x3 cells around it, with centres anywhere in their cell and about a quarter of the cells left without a clump, so clumped cover no longer lines up in rows at grazing views (cover format version 3)."}
- {"area":"engine","text":"Ground cover (grass) no longer grows on roads, and a cover layer can name path or mud terrain layers in source.avoid to stay off them."}
- {"area":"engine","text":"Windows crash reports list each frame as module+offset, which scripts/crash/symbolize.ps1 resolves against a release's PDBs; a release build's backtrace alone has no names."}
- {"area":"engine","text":"The Rust crowd (the default on two or more threads) no longer allocates memory every tick: a scene with navagents walking runs at zero allocations per frame again, as it did on Detour's crowd."}
- {"area":"engine","text":"A behaviour with no props now gets an empty object as
ctx.propsinstead of null, soctx.props.speedno longer throws; the native host, the web host and the test mock agree."} - {"area":"engine","text":"The engine's TypeScript packages use zod 4.6.6 or newer, which fixes advisory GHSA-mrhx-c7xc-m3w5 (high)."}
- {"area":"engine","text":"After a lost graphics device is rebuilt, the scene comes back as it was drawn: meshes as registered (virtual geometry again), the terrain, the HD look, sky and water, splat captures and user-shader textures. A rebuild that fails part way leaves everything for the next attempt."}
- {"area":"engine","text":"In a window, a third-person camera-relative character could walk a slightly different way than the same input does headless or in a replay, because a frame drawn between two game ticks left the camera where the picture was drawn from; drawing no longer changes the game."}
- {"area":"engine","text":"An exported game now carries the textures its particle effects name by path (a sprite's, a ribbon's or a decal's
texturebeside the*.vfx.jsonfile), so its effects look as they do in the editor instead of drawing the built-in sprite; an effect naming a texture that is not there refuses the export (vfx-texture-missing)."} - {"area":"engine","text":"An export now packs an effect that a particles component, in a scene or a prefab, names by a *.vfx.json path (with the textures it names), and refuses with vfx-effect-missing when that file is in neither the project root nor the scene folder. Such an effect used to be left out, so the game shipped the emitter with nothing to draw."}
- {"area":"engine","text":"An export now packs every file a component names and the files those name in turn (a terrain's .terrain.json, its layers' material files and their textures, a stamp's height image, a foliage layer's .instances files, as before a road's .road.json), and refuses an export whose referenced file is missing, naming the scene, entity, component, field and path, so a game with a terrain no longer ships with no ground."}
- {"area":"engine","text":"An exported project whose prefab names a file beside a scene other than the startup scene (for example a material in a track folder) now loads that scene; the prefab's asset paths are packed from every scene's folder, so they match the scene's own instead of failing with prefab-id-collision."}
- {"area":"engine","text":"Exporting a project whose scene sits in a folder (scenes/main.scene.json) no longer refuses the scene's own screen effects and shader materials as missing: the shader pack read their paths from the project's root instead of the scene's folder. The lantern-hollow sample exports again."}
- {"area":"engine","text":"A project export with several scenes no longer packs its startup scene twice: it is packed once, at its own project path, as the editor's export already did, so its models, textures and sounds ship once. Sprocket Rally's payload went from 34.3 MB to 21.5 MB. Single-scene exports are unchanged."}
- {"area":"engine","text":"The export package's branded-export tests yield to the event loop after each test, so vitest's worker answers its RPC on a loaded Windows machine instead of failing the run after a 60 s timeout with every test passed."}
- {"area":"engine","text":"Far birch and other fine-twigged trees no longer look heavier as impostors: an impostor's distance mips keep the coverage its full-size image shows on screen. Impostors baked before this rebake once."}
- {"area":"engine","text":"Far tree impostors keep their crown's area: sparse conifers and birches no longer thin out at a distance (a fir at 1000 m kept 85% of its mesh's area, now 100%). Impostors baked before this rebake once."}
- {"area":"engine","text":"Very distant sparse trees (birch) keep their true size: an impostor's smallest mips now stop at 24 or more texels a frame. Impostors baked before this rebake once."}
- {"area":"engine","text":"A distant tree drawn as its impostor now matches the brightness of the tree up close when the sun is behind the camera (a fir was about a quarter darker)."}
- {"area":"engine","text":"Generated trees no longer render neon lime in HD: the light a leaf lets through now follows how dark its own colour is, instead of glowing at full brightness in the leaf's hue. Cooked plants re-cook once (generator version 13)."}
- {"area":"engine","text":"Backlit leaves glow a natural green instead of a neon lime, and the inside of a tree canopy is lit again rather than nearly black."}
- {"area":"engine","text":"Alpha-tested foliage keeps its leaf area at a distance: a masked texture's smaller mips now keep the coverage a filtered sample sees, so sparse leaves no longer vanish or swell far away. Masked textures cook again once."}
- {"area":"engine","text":"One script can no longer redefine a ctx handle member (such as entity.position) for every other script in the game: the handle prototypes are frozen once the engine has built them, natively and in the browser."}
- {"area":"engine","text":"Pitched roofs over an odd span (3 or 5 cells) now raise their gable ends to the ridge's peak, closing the wedge gap that stood under each gable."}
- {"area":"engine","text":"The asset gate now counts triangle strips and fans (n-2 triangles) and instanced nodes (multiplied by their instance count, bounds include every instance) the same way the TypeScript measurer does, and rejects point and line geometry with a new non-triangle-geometry check."}
- {"area":"engine","text":"Ground in the shade of a plant, a fence or anything else close above it is no longer near black with ray-traced global illumination on: the screen-space ambient occlusion no longer darkens shade the global illumination already accounts for."}
- {"area":"engine","text":"Tree crowns no longer block global illumination almost completely: light now reaches trunks and undergrowth under a canopy, so they are less dark. The crown's openness to global illumination is 40% (picked by Sean on the round-2 sheet)."}
- {"area":"engine","text":"A material file with transmission, such as the glass preset, now draws as clear thin glass in HD. It used to come out as an opaque white ball, because the file's default alphaMode (\"opaque\") overrode the transmission. A mask still keeps its cut-out."}
- {"area":"engine","text":"A model with one mesh that has no UVs (a character's teeth, say) no longer loses every texture on the whole model: only that mesh draws without its textures' detail, and loading prints a
mesh-uv-missingwarning naming it."} - {"area":"engine","text":"
profile explainreads each GPU pass's time per GPU-timed frame. When the GPU timer falls back to timing 1 frame in 4, a pass used to read a quarter of its time, and a GPU-bound window could lose its hot-pass finding."} - {"area":"engine","text":"Characters in a crowd no longer climb each other or get flung off at high speed: a character's ground velocity is now the ground's own motion, another character is never ground from beside it, and a character turning to look round no longer swings a rider standing on it. A ground moved only by a script teleport (no velocity of its own) gives no carry when you jump off it."}
- {"area":"engine","text":"The built-in grounding behaviour now plants feet where the walk puts them and moves them with the ground, so a walk keeps its stride on slopes; it no longer hits the character's own collider (which planted both feet half a metre up) or stops working on an animator with no look-at."}
- {"area":"engine","text":"HD reflections inside closed rooms no longer pick up a faint glow of the sky: mirror-like surfaces that only see the room around them now stay as dark as the room. Screen-space reflections also trace the same on every graphics driver."}
- {"area":"engine","text":"HD: ray-traced GI no longer turns a surface without a usable normal (a mesh with zero normals, or a zero or non-finite normal in the G-buffer) into NaN. The NaN slipped past every threshold, stayed in the GI history, and the upscaler spread it into black blocks along edges, a whole black wall panel on the fantasy-town kit. GI reads such a normal as facing the camera."}
- {"area":"engine","text":"Tinted glass in HD now tints what shows through it by its base colour, as glTF's transmission does: green glass at full transmission draws the scene behind it green, where it used to let it through untouched. Glass with a white base colour and no colour texture draws exactly as before, and a frame with no tinted glass in view is unchanged."}
- {"area":"engine","text":"On HD, an instance's colour (a mesh component's
color, anentity.set(\"material\", ...)tint, a material'svariation) now tints a layered material whose layers read the vertex colour; it was dropped, and it also skewed the layer masks. The masks read the vertex's own colour, and the instance colour tints the surface on the raster path and through virtual geometry alike."} - {"area":"engine","text":"HD: an instanced mesh whose mesh draws as virtual geometry now shows its
colortint (it was drawn untinted); tinted sets draw through the raster path until virtual geometry carries a per-instance tint."} - {"area":"engine","text":"HD: a projected layer over a material mapped by its UVs (a kit's palette with a tiled set over it) now projects. It drew with the base's shader variant, which has no projection, so the layer read the palette's UVs and smeared into streaks."}
- {"area":"engine","text":"In HD with ray tracing, a stylized custom shader whose ambient() reads the sky (env_specular, ambient_irradiance) now shows its own look in reflections instead of its fallback colours."}
- {"area":"engine","text":"HD keeps tinted instances (an instanced mesh's
color, per-instance colour) on virtual geometry instead of drawing them raster: a forest of 101k trees in four tints went from 43-136 ms of GPU time back to the untinted 4-5 ms. Only a see-through colour (alpha below 1) or a fade still draws raster."} - {"area":"engine","text":"The HD renderer's first-frame warm-up, which builds every quality's pipelines and can take over 20 seconds on a cold pipeline cache, is no longer recorded as a hang by the crash watchdog; and a crash or hang report's
exe sha256is now the hash of the executable that ran, with the.sha256beside it named only when it disagrees."} - {"area":"engine","text":"The stock HUD's numbers are readable:
ctx.hud.timer(2)showstimer: 0:02.0instead oftimer: 2.0000001043081284, and any other number without ameta.hudstyle shows at most two decimals (score: 12.3,ammo: 0.67)."} - {"area":"engine","text":"The trunk and branches of a far tree drawn as an impostor no longer glow orange when the sun is behind it: only the leaves let light through, as on the tree up close."}
- {"area":"engine","text":"Far conifers drawn as impostors no longer turn pale yellow-green against a low sun: their needles keep the colour the tree has up close."}
- {"area":"engine","text":"Far trees drawn as impostors now light like their leaves (light through the leaves when the sun is behind them), so a backlit tree in the distance is no longer a dark disc. A tree held at the impostor switch distance no longer shows a fixed grid of dots, and the ray-tracing geometry buffers grow in smaller steps, so a large forest holds less unused GPU memory."}
- {"area":"engine","text":"A stick-driven character playing in-place clips (no root motion) now turns to face where it moves, as a root-motion character already did, instead of running sideways or backwards."}
- {"area":"engine","text":"A scene's
meta.input.activenow picks the context live at load, restart andloadScene. A scene with agameplayand amenucontext and\"active\": \"menu\"used to start ingameplay. Hot reload ofmeta.inputstill keeps the context the player is in."} - {"area":"engine","text":"The critic's kart wall-hit feel test puts its wall where the impact probe's drive actually goes (z -12 to 0); it had been passing on a bump against the scene's bounds after the car left the floor, which a controller sized to its authored 0.5 m capsule no longer raised."}
- {"area":"engine","text":"In HD, the shallow water of a lake no longer shows pale vertical stripes below the peaks that touch the top of the picture: a reflection that climbs out of the top of the frame now shows the sky instead of the colour at the frame's edge. HD water reflections also fade gradually into the sky where the picture runs out (near the frame's edge, for rays turning back toward the camera, or for uncertain hits), instead of ending in a hard line."}
- {"area":"engine","text":"Leaf cards and other cut-out textures keep their coverage in distant mip levels, so a far canopy keeps the density it has close up instead of thinning out or swelling, and in HD their edges are softened over frames instead of stair-stepping."}
- {"area":"engine","text":"A Linux game or engine now starts on a system without the ALSA sound library (libasound.so.2): it runs without sound and says once why, instead of failing to start."}
- {"area":"engine","text":"The navmesh rebuild, 10K contract validation and particle CPU benchmarks no longer fail on a busy machine: like the other timing tests, they measure the budget but do not assert it above 0.75 load per core, and still fail past four times it."}
- {"area":"engine","text":"Reloading a material asset in a running world (the editor's material panel) now reads its layers' material files again, so a layer whose own file was edited draws its new values under HD instead of the copy cached at load."}
- {"area":"engine","text":"Contacts against triangle-mesh colliders (road barriers, mesh-collider levels) and terrain heightfields now report the impulse the solver applied, where they reported none before. A vehicle's
contactblock now sees a road barrier: a kart nosed into the Kart Starter's wall with\"contact\": {}is turned along it and drives off, instead of sticking. Collision events (onCollision'simpulse),GET /contactsand the critic's impact probe see the real impulse against meshes and terrain too, where they read 0 before: a behaviour that ignored hits under some impulse now hears them there."} - {"area":"engine","text":"A 0.5 project that names the retired starter sounds (
builtin:sfx/…,builtin:music/…,ambient/,voice/), which has not opened since 0.6.0, opens again afterproject migrate --apply. Each sound now points at a placeholder file the engine writes beside the scene (a short beep, or silence for music and ambient), the report lists every one for you to replace with a sound of your own, and--restoreremoves them again. Validating a project from an older engine now names the command that upgrades it (project migrate --dry-run, then--apply), the engine's--helplists--applyand--restore, and--inforeportsprojectMigrate(the result version--applyprints), so a launcher can tell an engine that applies upgrades from one that only reports them."} - {"area":"engine","text":"A navmesh build with AgentParams::detail_sample_dist below 0.9 now turns the detail mesh off as documented, instead of looping until the process ran out of memory or crashed; a NaN, infinite or negative detail setting, or a cell size or height that is not positive, is refused by name before anything is built."}
- {"area":"engine","text":"A snapshot restore in a meta.nav.live scene puts back the navmesh of the restored static colliders: going back to before a door closed routes through the doorway again, where it kept the newer mesh. A restore inside a rebuild's 6-tick window installs the restored state's mesh at once (docs/API.md)."}
- {"area":"engine","text":"A live edit's navmesh rebuild (the editor's edit during Play, an agent's change to a running Play, or any edit while a replay records or plays) goes in on a fixed tick,
NAV_LIVE_INSTALL_TICKSafter the edit, so a recording and its playback route the same however fast either runs. A file reload outside a replay (--watch, F5) still installs as soon as its build is done."} - {"area":"engine","text":"A navagent that is teleported (ctx.entity.teleport) or put back by a snapshot restore now walks on from where it was put: the crowd agent moves with it, keeps its target and plans to it again. Before, the next tick put it back where the crowd had it. Navagents also join the crowd in scene id order, so the crowd updates them in the same order however the world was built or respawned."}
- {"area":"engine","text":"A navmesh baked beside a scene (
<scene>.navbake) is now the one its load installs. Before, the scene's path was set only after the navmesh was built, so the bake was never found at load: the desktop rebuilt the mesh with Recast instead, and a web build (which has no Recast) had no navmesh at all."} - {"area":"engine","text":"A level wider than one navmesh tile holds (over about 620 m across at a player's cell size) now gets a navmesh: it is built as 64 m tiles linked at their seams, so paths, crowd agents, declared and automatic jump links and the critic's reachability work across it. A kilometre-square ground builds in about 2 seconds instead of being refused. Levels that fit one tile are built exactly as before."}
- {"area":"engine","text":"NPCs can now walk up a ramp or a flight of stairs built as solid shapes standing on a floor; before, the parts more than a step above the floor counted as blocked. Pillar and table tops that no step reaches stay out of bounds."}
- {"area":"engine","text":"A despawned NPC now leaves its type at once: a spot it had reserved (cover, a post) is free for the others on the next tick instead of staying taken until the reservation ran out.
GET /npc/pendingshows what scripts have asked of the NPCs (damage, talk, stimuli, reputation) that their next tick will apply."} - {"area":"engine","text":"A vehicle with an
offRoadblock driving on a road laid at the very height of the ground under it now reads on the road. The wheels' rays hit the road and the ground at the same distance and reported one or the other tick to tick, so about half the time the vehicle was slowed and steered \"back\" to the road it was on."} - {"area":"engine","text":"An \"overcast\" sky (cloud coverage 0.95) is now a closed deck: the cloud shader's coverage threshold used to leave large holes in it even at full cover. From coverage 0.9 up the weather-map threshold and the share of shape noise the threshold may cut away both ease toward a full deck, so overcast (0.95) and storm (1.0) decks close, and so does any written coverage above 0.9. Presets at coverage 0.9 or below, fair, broken and clear included, draw exactly as before."}
- {"area":"engine","text":"Menus can be navigated with a gamepad D-pad (buttons or axes) and the left stick, however the pad reports its directions."}
- {"area":"engine","text":"Captures (POST /capture, play.capture, an engine run with --render-on-request) now show particles, from particles components and from ctx.particles.emit; before, a world that was only stepped and captured had none in its pictures."}
- {"area":"engine","text":"A
velocity-facing particle now streaks along its motion as the camera sees it, through the perspective, on both renderers. It used the velocity's part along the camera's right and up, which is near zero for anything flying at or away from the camera, so a speed line or an exhaust jet seen from a chase camera pointed any way at all instead of out from the vanishing point."} - {"area":"engine","text":"The shader pipeline cache no longer adds hundreds of megabytes of memory: it is read only for scenes that need it, kept in one file per renderer profile, and capped at 64 MB (a larger file is ignored and replaced)."}
- {"area":"engine","text":"The compiled-pipeline cache no longer grows without bound: its folder is held to 64 MB, removing the least recently used files first (another graphics driver's, say), a cache file that has grown past the cap on its own starts again, and leftovers from unfinished saves and the old hd-pipelines folder are cleared."}
- {"area":"engine","text":"The compiled-pipeline cache no longer grows with every engine update: it is kept per engine build, and a new build removes the previous build's file for the same graphics card instead of adding to it."}
- {"area":"engine","text":"A scene or project manifest with a wrong type, an unknown name or cut-off JSON is now refused in plain words instead of serde's:
field \"fov\" must be a number, not the text \"sixty\"(wasinvalid type: string \"sixty\", expected f64 at line 1 column 700),unknown component type \"wheell\"; did you mean \"wheel\"?(was every one of the 37 component types), andthe JSON ends before it is complete: a list ([ ... ]) is still open. A manifest fault names its key path (at /schemaVersion: ...). The line and column are kept for a file of more than one line and for a JSON syntax error."} - {"area":"engine","text":"In a networked session (HostConfig::networked) a script's Math.sin, Math.exp, Math.pow, Math.hypot and the other transcendental functions now give the same bits in the browser, on Linux and on Windows: they are the libm crate's algorithms in plain JavaScript (portable_math), where before each engine's own could differ in the last bit and split the peers. The
**operator, which no Math reaches, is refused at load in such a session; use Math.pow. ctx.world.road answers now agree bit for bit between the browser and the desktop in every session. Single-player scripts keep the engine's faster built-in Math."} - {"area":"engine","text":"A prefab asset key that clashes with the scene's now says which field differs (for example the triangle count of a built-in mesh) and both values, instead of printing the same text twice."}
- {"area":"engine","text":"New project and
project.createnow make a project in a folder that holds only a fresh git checkout's files (.git,.gitignore,.gitattributes, a README, a LICENSE), leaving them as they are; a folder with anything else in it is still refused."} - {"area":"engine","text":"A hot reload or live edit that removes an entity with a light, including a light a script spawned, now stops that light lighting the scene; before, it kept shining until something else changed the lights."}
- {"area":"engine","text":"A networked co-op session now computes the same crowd on every computer. From the tick a remote player sits down, the session is deterministic and its crowd is the same on any number of cores (a 2-core computer used a different one before). argus run --deterministic starts a session that way."}
- {"area":"engine","text":"Replaying a session through another camera (--replay-camera), or ejecting the editor's view during Play, no longer turns a camera-relative player's stick, so the replay walks where the recording walked."}
- {"area":"engine","text":"A replay now presses the same menu buttons at any window size: where each pad step through a menu landed is recorded (replay format 2), so a menu whose buttons wrap differently in another window no longer lands on other buttons on playback; older replay files still load and play as before."}
- {"area":"engine","text":"A world restored from a checkpoint now answers ray and shape casts exactly as the world it was saved from: the first tick after a restore (and the tick after a body is added) no longer swept shapes differently from every other tick, and a restore no longer forces slow brute-force casts until the next step. Checkpoints saved by this build are a new version (8) that older builds refuse to load; checkpoints from older builds still load."}
- {"area":"engine","text":"A world restored from a snapshot, in particular a fresh one such as a late joiner, now steps exactly as the world it was saved from from its first tick: putting back a body velocity it already had no longer marks the physics body changed (which re-processed the static floor on the next step), and input a behaviour gave a character the engine drives, waiting for its next pass, now rides in the controller state as pending."}
- {"area":"engine","text":"Restoring a snapshot no longer makes every standing character land on the next tick: characters that were standing are put back on their floor, so behaviours no longer hear a burst of land events (and a restored run hears the same events the original did)."}
- {"area":"engine","text":"A retarget map now carries motion in world space with the rest poses aligned, so characters whose bones are rolled differently or that rest in an A-pose or with bent knees play a clip's pose instead of crossing their legs or holding their arms 45° off. It also warns about maps whose left and right look swapped."}
- {"area":"engine","text":"Cars and karts no longer meet a raised lip where a road joins the terrain carved under it. Since roads were drawn 5 cm above their points (so a floor at the same height cannot hide them), their collision surface had been raised with them; it now stays on the road's points again and only the drawn road is lifted."}
- {"area":"engine","text":"A road's terrain conform (carve or flatten) no longer digs a trench beside a road that climbs or falls: the ground on the kerb and shoulder now meets the road's own height there, where it used to sit up to about 0.8 m lower beside a steep stretch."}
- {"area":"engine","text":"A road with a crown (
crossSlopePct) no longer shows a hard light line down its centre when you look towards the sun: the two halves' shading now blends over half a metre either side of the centreline. The road's collision surface is exactly as before, so cars drive the same."} - {"area":"engine","text":"Closed roads that climb and fall no longer come back twisted at the seam: the road surface stays level across (only authored bank tilts it), so karts stop sliding off."}
- {"area":"engine","text":"A road laid on the ground of a new project is visible again. A road at the same height as the floor (y = 0, as in a new project) used to vanish wherever it crossed the floor; road surfaces now sit 5 cm above their points."}
- {"area":"engine","text":"A character with a controller now starts facing the way it was placed, so a root-motion roll or lunge travels along its facing. Before, a character placed turned round rolled backwards and one placed sideways rolled sideways."}
- {"area":"engine","text":"Animator rootMotionFrom reads the joint's travel in the model's frame, so a clip pack on a rig whose root bone is turned (a Z-up mannequin) travels along the ground and not along the root's own axes"}
- {"area":"engine","text":"With HD ray tracing on, a very large static mesh (millions of triangles, more than the graphics card can bind for ray tracing) is now ray traced through an automatic simplified copy, so it casts ray-traced shadows and shows in reflections and global illumination instead of being left out; the copy is rebuilt on each load, which adds load time for a huge mesh, and the game still draws the full-detail mesh (runtime code
render.hd.rt_mesh_proxied). Small plants below the ray-tracing size floor (rt_min_radius_m) now keep their ray-traced sun shadows while reflections and global illumination still skip them."} - {"area":"engine","text":"Ray-traced lighting and reflections now see a far forest's darker canopy tone instead of the ground's plain colour, so light bounced from distant forests matches what is drawn."}
- {"area":"engine","text":"Lakes and the sea with ray-traced reflections no longer show flat violet speckles on the mirrored shore: the water's mirror ray now shades terrain hits like the rest of the ray-traced scene."}
- {"area":"engine","text":"
argus run --frames N(a run that ends by itself, with no--serveor--watch) now exits 1 when a behaviour threw, ran away or was missing, and says eachscript-erroronce instead of repeating them all at the end. A missing behaviour's message now leads with the file that is not there, not with building@argus/gameplay, and a module with no default export says so instead of QuickJS's \"Error converting from js 'undefined' into type 'object'\".--recordand--record-dataruns say each error once too and still exit 0, since what they wrote is their result."} - {"area":"engine","text":"Running a scene file that sits inside a project now draws it with that project's renderer settings (render.profile, backend and quality), so an HD project's scene is no longer drawn by the standard renderer when run on its own. A new --render standard|hd flag on run overrides the renderer for one launch."}
- {"area":"engine","text":"A scene over its triangle budget now says so in Play, argus validate, the editor build log and the export note, naming a budget that would hold it."}
- {"area":"engine","text":"A behaviour can no longer reach the real clock or the page's own built-ins: Object.getPrototypeOf(Date).now() read the wall clock (in the browser and on the desktop), the browser's script Math led to the page's unseeded Math.random, and a name the sandbox refuses (globalThis, Function, eval and the rest) passed its check when written with a Unicode escape such as globalThis. Date keeps its statics and methods, and a class can still extend it."}
- {"area":"engine","text":"A character driven by its behaviour (input: \"script\") no longer keeps running its legs after the script stops calling ctx.controller.move: the animator's inputSpeed and strafe parameters now read only what was asked for this tick, as they already did for the stick."}
- {"area":"engine","text":"A behaviour can no longer compile text into a function or reach the page it runs in, whatever the word list misses: the global
Functionis the same refusing stand-in that.constructoralready gave (instanceof Functionstill holds), the authoring runtime gets the same seal, and in the web build every page global that the native host does not give a script,evalandfetchamong them, is hidden from a module. The word check now also reads the code inside template${…}substitutions, and it refusesimport(…)andimport.metawherever they appear in the source. Networked peers must run the same release: the handshake digest changed."} - {"area":"engine","text":"Games on the standard renderer reserve GPU memory in smaller blocks (engine-wide; HD unchanged): on an RTX 3080 most reference scenes use 134 MB of dedicated VRAM instead of 202, with the same load times. Water-critic-alpine's frame is 25 us slower in 4 of 6 runs (cause not pinned down); the 10-scene table is in docs/PERFORMANCE.md."}
- {"area":"engine","text":"Effect sprites now fade softly into the ground and walls on the standard renderer and the web runtime, as they already did in HD, instead of being cut into hard half-discs where they cross a surface. render.soft.distance sets the fade; without it the default is 0.3 m."}
- {"area":"engine","text":"A hull floating in very thin sea water no longer shows a jagged, stair-stepped strip along its waterline: the sea reads its water thickness along the straight view and bends only the colour of what it sees through the water."}
- {"area":"engine","text":"
--self-testnow plays from no save in a save folder of its own, unless--save-dirorARGUS_SAVE_DIRnames one. Before, it used the player's real save for the application, so one scenario's saved best score made another scenario's \"Best: 0\" step fail on the next run."} - {"area":"engine","text":"An exported game's
--self-testnow finds a scenario however it is named:play,play.json,selftest/play.json(either slash) or a path relative to the folder the game was started from. A missing scenario names the one path looked for, notselftest/selftest/play.json.json. Exports made from the editor now pack the project'sselftest/scenarios, asengine exportalready did."} - {"area":"engine","text":"A self-test can now steer a car or kart. A step such as
{ \"axis\": \"steer\", \"value\": 1 }was refused with \"expected an array of length 2\"; a bare number is now read as[1, 0], and docs/SELF-TEST.md explains that a one-axis control like steer or throttle reads the first number of the pair."} - {"area":"engine","text":"A texture that arrives after the scene started (a streamed or replaced texture) now shows on shader materials on the standard renderer; before, they kept drawing the placeholder."}
- {"area":"engine","text":"
World::sim_digestnow tells NaN, infinity and negative infinity apart. It used to hash every serialised part through JSON, which writes all three asnull, so a platform that produced NaN where another produced infinity read as agreement. A value that cannot be digested now panics with the reason; it used to hash as nothing on both sides, which also read as agreement."} - {"area":"engine","text":"A scene sky written without
rotationorintensity, which the contract requires, now fails with aschema-shapeerror that names the field and the value to write (\"rotation\": 0), instead of \"expected number, received undefined\"."} - {"area":"engine","text":"A restored character now walks the way it was heading.
GET /snapshotcarries the controller's heading (yaw, whichlookturns; before, a restore read it off the entity's rotation, which a turned player does not change) and the mover squeezing it (squeezedBy, so a restore mid-squeeze raises no secondcharacter-squeezed). Both are optional: a snapshot from an older engine restores as before."} - {"area":"engine","text":"POST /snapshot now recreates entities the live world has lost (spawned ones and despawned scene ones) instead of skipping them."}
- {"area":"engine","text":"A copy spawned with ctx.world.spawn({ like }) after a snapshot is restored now gets the same like#N id as in a run that never restored, in the same world or a fresh one (a late joiner): the per-source spawn counts now ride in the snapshot as spawn_counts. Before, a restored world kept counting from its later count and a fresh one started again at 1. A snapshot from an older build, without spawn_counts, still restores counts only from the copies alive in it, so a copy spawned after restoring one can reuse an id a despawned copy had."}
- {"area":"engine","text":"Split screen: a terrain's ground cover grows around every player, not only player 1. Its window spans every view's reach (at the same 1 m texels a single view has), up to 768 m across; past that, view 1 keeps its full reach and the others' cover recedes gradually rather than vanishing at once. The
splat-view-outsidewarning measures from the nearest view. A single view bakes exactly as before."} - {"area":"engine","text":"Split screen: level of detail and culling are chosen for every view, not only view 1. View 2 no longer draws a mesh at the level view 1's distance asks for, and an instanced mesh's or a terrain's cells that only view 2 sees are no longer dropped. A mesh draws the finest level any view asks for; a cell is culled only when every view culls it. A single view chooses exactly as before."}
- {"area":"engine","text":"In split screen, a player's camera-relative stick (a controller with inputBasis \"camera\") now walks in the frame of that player's own view, the one that follows or frames their character, instead of always in view 1's; a player no view looks at still uses view 1, as before."}
- {"area":"engine","text":"The standard renderer now draws a material's ORM, metallic-roughness and occlusion maps (roughness, metallic and ambient occlusion), as HD does, for material files and imported models. Materials without these maps draw exactly as before."}
- {"area":"engine","text":"A snapshot restore (the critic's playtester restores between probes) puts ctx.state back into the same object, so a behaviour that kept const st = ctx.state from init keeps writing the live state."}
- {"area":"engine","text":"
ctx.entity.teleportnow stops a moving body as well as a character, as the API says it does. Before, a vehicle kept its speed, so the Kart Starter's reset (R) and its fall-off respawn sent the kart off down the track at about 18 m/s."} - {"area":"engine","text":"A game's first launch no longer waits for its terrain cache: the cache files are written on a background thread after the load instead of during it. On Windows that took about 1.3 s of a new player's first launch (about 1,000 small files), while computing the terrain took about 35 ms."}
- {"area":"engine","text":"A terrain whose edge stands in shallow water under the scene's sea no longer ends the shallows in a straight dark line: past the edge the drawn ground slopes down into deep water, so the water fades from turquoise to the open sea's blue. Collision still ends at the edge."}
- {"area":"engine","text":"A terrain file with more than 8 layers is now refused when it opens, with an error that names the layer count and the list, instead of loading and then silently not being drawn; the scene capture example also stops with a non-zero exit when a terrain in the scene was not drawn."}
- {"area":"engine","text":"A terrain's per-cell render meshes (with the macro slope in the vertex colour) are built on all cores instead of one cell after another, taking about 0.2 s off the load of a 64-cell terrain such as water-critic-alpine."}
- {"area":"engine","text":"Terrain no longer looks glossy or metallic in the standard renderer from afar (a layer's lost normal-map relief now roughens it), terrain layers can be tinted past their material's colour to calibrate a texture set (snow white, grass green), rock on slopes can be kept off ground under the sea, snow gives way to rock raggedly on steep faces, and the terrain material costs less GPU time (ray-traced hits take a cheap path)."}
- {"area":"engine","text":"A terrain's level-of-detail chain is meshed with its levels side by side, sharing the cores, and a cell's border agreement re-propagates only the triangles an edge can reach. The meshes are unchanged (the same bytes); the CPU mesh build of a 64-cell terrain such as water-critic-alpine takes about 45% less wall time."}
- {"area":"engine","text":"A scene whose terrain has roads loads faster: the ground under the roads is shaped on every core (about 60 ms off a 2 km terrain)."}
- {"area":"engine","text":"Low-contrast terrain layers (sand, snow, fine soil) no longer show their texture repeating as a grid of dots in the middle distance, and a surface altitude layer whose end lies under its start now lays its layer below that height (a lighter seabed under shallow water)."}
- {"area":"engine","text":"Snow from a terrain's altitude layers now follows the mountain's overall slope instead of every carved gully, so HD peaks keep their snow cover; truly steep crags still show rock."}
- {"area":"engine","text":"Rocks and other props buried in terrain draw as they did before: the terrain keeps its place in the draw order, and a scene with terrain loads as fast as before."}
- {"area":"engine","text":"Scatter keeps each placement's footprint off a terrain's volume rock, not only its centre, so a boulder or a trunk at the foot of a cliff no longer stands half inside it; procedural and mesh rocks keep their own reach off it too.
TerrainState::hole_quad_withinis the check. Terrains without volume ops place exactly what they did."} - {"area":"engine","text":"
volume.cliffbuilds over large, coarse terrain. Before this, a hole group joined to the rest only through a passage one quad wide was refused (\"has 2 surface edges where one is needed\"), as happened over the alpine valley's walls at 4 m samples. The footprint now widens such passages. The cook is also faster where the rock is tens of millions of edges: zipping an alpine valley side went from 93 s to 6 s, and the 400 m test wall from 1.4 s to 0.93 s, with the same output. The refusal message now says where each surface edge is."} - {"area":"engine","text":"In HD with an atmosphere sky, see-through surfaces, particles and waterfall mist seen against the sky no longer vanish behind it."}
- {"area":"engine","text":"A vehicle's tyres now hold against a steady push near a standstill. A car with its handbrake on no longer creeps down a slope (it slid 0.4 to 1.4 m in 10 s on 5 to 15 degrees), and a kart nosed into a wall with the throttle held is no longer swung round until it faces the wall square on. It is still stopped there: steer away from the wall, or reverse."}
- {"area":"engine","text":"A back (Escape) that a non-dismissible screen refuses is no longer swallowed: the screen stays, the press reaches the game's action map so
ctx.input.pressed(\"uiBack\")sees it, and it never quits the window, in a real window and overPOST /inputalike (docs/UI.md, \"Input\")."} - {"area":"engine","text":"A game's own fonts draw again. Since October's default-font change, DejaVu Sans Mono sat in every font chain as a last fallback, and any text that didn't name a font exactly as the font names itself, at a weight the font has, came out in monospace (Sidecar Sprint's whole UI). It is gone from the chain, so that text draws in the project's first font as before. Greek and Cyrillic outside a project's own fonts have no engine fallback at run time for now; an export still packs DejaVu when a shipped language needs it."}
- {"area":"engine","text":"A
ctx.ui.fxone-shot, or a stylesheetanimation, no longer fades to near-invisible and stays there when the same screen gets astyle:,data-orclass:write every frame (a minimap marker or a meter moving while a placepops). Each such write re-took the preset's base from a style that still held this frame's offset and applied the offset again."} - {"area":"engine","text":"A hidden image (
display: noneon it or on a container around it) no longer reportsui.layout.image-zero-size. A HUD that shows an item icon only while an item is held used to log a warning for every icon it hid."} - {"area":"engine","text":"A thick
-webkit-text-strokeno longer slows the game down. An outline is now drawn as one copy of each glyph, dilated once and cached, instead of the whole text drawn again hundreds of times around itself: a 12 px stroke was about 260 extra text areas prepared every frame, and Sidecar's results screen fell to 25 fps on it. Outlines look the same (round, antialiased); a stroked label whose scale animates costs one new glyph per letter per size."} - {"area":"engine","text":"Padding on a UI text node now moves its text inward, as in CSS. Before, padding made a label's background bigger but left the words against its left and top edges (text fields and bitmap-font text too); only a border moved them. Screens that centred their text to work around it still look the same."}
- {"area":"engine","text":"A project's own
@tokensnow apply when it declares no@theme. Before, a game that named its palette in@tokens(one look, nothing to switch) had everyvar(--name)of its own refused at run time as an unknown token, and only adding a theme block made them resolve. Projects without@tokensdraw exactly as before."} - {"area":"engine","text":"Scenes with user-shader instances far apart in the draw list upload their per-instance data in a few small runs instead of one block spanning everything between them, which lowers staging memory."}
- {"area":"engine","text":"Custom shaders can no longer black out the screen with an infinite or invalid colour, crash the editor with a pathological file, lose their object on a hot reload that changes blending, or show the wrong texture after streaming; files saved with a byte order mark now load."}
- {"area":"engine","text":"
argus validateno longer saysokfor a scene whose behaviour script is missing or does not compile, or whose model or texture file is not on disk. It looks whereargus runlooks, compiles each.tsbehaviour as the run does, and reports each problem under a newfileslist in--json(codesbuild.module-not-found,build.transpile-failed,build.toolchain-unavailable,build.asset-missing, the same as the build's) and exit code 1. A tool the machine lacks (no esbuild, no@argus/gameplaybuild) is a warning, not a failure."} - {"area":"engine","text":"
argus validatenow checks the contract's length and range bounds, ascritic.checkdoes. Before, a scene the critic failed withschema-shapecould pass validate: a foliage layer with more than 32 prototypes, an empty spring-chain joint name, acustomDatalist over 8. Each such value is aschema-shapeerror at the pointer the critic names. The bounds are generated from the one schema (pnpm gen:rust). The engine still loads such a scene as before."} - {"area":"engine","text":"
argus validatenow fails a scene whose JavaScript (.js) behaviour has a syntax error. It reportsbuild.transpile-failedwith the file and line, as it already did for a TypeScript behaviour. Before, the scene passed validation and then failed to load."} - {"area":"engine","text":"A car or kart added to a new project now drives with WASD straight away. A new project's controls have no throttle or steering, so a vehicle sat still until you added them; it now drives from the walking keys (W forward, S brake and reverse, A/D steer, Space handbrake). A game that sets up its own vehicle controls is unchanged."}
- {"area":"engine","text":"Captures (
play.capture,capture_request, clips) of an HD world now show the hit decals particle effects make, the same ones the window shows; before, they were missing from capture frames and the hits were counted dropped."} - {"area":"engine","text":"A quality change (Auto settling) no longer respawns the waterfall mist, which regrew from empty; a failed
falls-mistoverride now warns once."} - {"area":"engine","text":"The splash crown droplets no longer die on spawn, the bow spray and the jet plume are round and low instead of long streaks, and the waterfall mist covers the plunge foot again."}
- {"area":"engine","text":"In the browser, a script whose first line is its export default no longer fails to load with the work budget on."}
- {"area":"engine","text":"A behaviour that sets a value of -0 (a turn of
0 * -rate, say) now sets -0 in the browser too, as it always did on the desktop: the web build sent it as 0, so a web game's state could differ from the same game's on the desktop by the sign of a zero."} - {"area":"engine","text":"In the browser, objects the engine hands a script (a shapeCast hit, an input action, axisParts, a water sample, camera.viewSize) now list their keys in the same order as on the desktop, so a script that prints or iterates one sees the same thing in a mixed match."}
- {"area":"engine","text":"In the browser, scenes with behaviours run again: the web runtime's embedded script copy had fallen behind its source (it lacked onCollisionStay's hook), so every behaviour stopped with a script error at load."}
- {"area":"engine","text":"On Windows, textures announced to arrive after the first frame (texture streaming) were never waited for or applied when the project folder was given in its long form."}
- {"area":"engine","text":"The workspace service has a
stopcommand, a busy--portnow names the port and says to pick another or leave the flag out, and a stale discovery file says how to start the service again.arguswith ARGUS_TEST_PANIC set and no command now writes a crash report instead of printing the usage."} - {"area":"engine","text":"A run that steps without drawing (headless, or recording data only) now reports every moving entity's current world position; worldPosition in --record-data stayed at the loaded pose, and an entity attached to a bone read as not moving."}
- {"area":"engine","text":"A young tree under the impostor triangle floor now draws its impostor at distance: a hinted plant at least 1.5 m wide is virtual geometry at any triangle count (a 37k-tree vista: raster rows 7,600 to 508, GPU 0.2 to 0.8 ms less on an RTX 5080)."}
- {"area":"agent","text":"
road.sample,entity.align ground: true, the terrain critic and the buildings and procgen tools now find a road whose file sits under the scene's folder (the Kart Starter'sscenes/tracks/loop.road.json), looking where Play and export look: the project root first, then the scene's folder. Before,road.sample {road: \"track\"}on a fresh Kart Starter answerednot-found."} - {"area":"agent","text":"A fresh agent session whose project names a
startupSceneno longer refusesscene.patch,terrain.createorbehaviour.writewithattach_tobecause \"no scene is open\". With no scene open, such a call works on the startup scene, leaves it open, and says so in its answer (opened). The refusal that remains (a project whose startup scene is missing) names that scene. It no longer tells a tool without asceneargument to pass one."} - {"area":"agent","text":"Sub-agents of one connection (
\"agent\": <name>) work on the scene their connection opened instead of being told no scene is open, and see what other agents have landed since their last read (a prefab of another agent's new entity works), while an edit to something another agent changed is still refused as stale."} - {"area":"agent","text":"The agent tools (project.create, project.open and the scene tools) now open a project on a Windows drive from WSL, or on the WSL share from Windows, so it can be authored there and run by the engine on the other system without a copy. The answer's otherOs field names the workspace service to start on that system; the editor still runs only on the system that owns the files."}
- {"area":"agent","text":"behaviour.write now writes self-test scenarios (selftest/<name>.json) the way it writes data files, checking each as the engine reads it, so an agent can author the scenarios critic.selftest runs."}
- {"area":"agent","text":"
critic.checkno longer ends with exit code -1073740791 on Windows after a passing check, and a critic process that does crash after printing its verdict is now reported as awarningon the answer (a crash before any verdict is refused with a message naming it)."} - {"area":"agent","text":"The playtester's animation check no longer reports a running character's feet as sliding during the run's flight phase, and it now says when a character walks backwards (its model faces away from where it goes) and how to fix it."}
- {"area":"agent","text":"critic.check warns missing-string when a behaviour hands ctx.hud.set or ctx.hud.prompt text instead of a key (ctx.hud.set(\"lap\", \"1/3\") draws [[1/3]]), naming the line; a key built from a known prefix (hud.coins.${n}) stays quiet. API.md's wind example draws a number."}
- {"area":"agent","text":"The critic's budget check now counts instanced meshes. An instanced mesh used to add nothing, so a town built with
instance: truelooked empty toover-budgethowever many pieces it drew. Now every instance adds its mesh's triangles and each instanced mesh is one draw call. The count comes from the.instancesfile, looked for where the engine looks for it."} - {"area":"agent","text":"critic.check_ui no longer reports
ui-contrastfor text at opacity 0 or under an ancestor at opacity 0 (the first frame of a fade-in draws nothing); partial opacity is still checked."} - {"area":"agent","text":"critic.play checks every argument before it launches anything and refuses a bad one as bad-input with the values it takes (speed 0.1 to 10, page from 0, section one of the sections); speed: 20 used to run the whole playtest and then answer tool-missing."}
- {"area":"agent","text":"critic.play and critic.check serve a page, section or full read from the kept run with the same arguments while no project file or the engine has changed, name that run (id and time) in the answer, and run again (saying why) when something changed; before, a section read after an edit answered the run from before it."}
- {"area":"agent","text":"The playtester's feel probes run on their own (a list of probes, no goal walk) on a game that opens on a title no longer report every control dead: they start from just past the title, as a full run does, instead of from before it."}
- {"area":"agent","text":"critic.check_ui no longer fails a finish screen whose only button is \"Race again\": ui-no-way-back takes a restart or a leaving said in a control's id or label (again, retry, replay, rematch, exit, leave, continue) as a way off, besides data-action."}
- {"area":"agent","text":"critic.check no longer calls every prefab unused when a script names them with a template string:
tiles/${kind}counts as using every prefab undertiles/, and a fully dynamicprefab:${x}`` suppresses prefab-unused for all with one info line saying why."} - {"area":"agent","text":"With no editor and no workspace service running, asset.import (models, sounds, fonts, scans and the paths/glob batch), asset.place and audio.synth now write into the project's files instead of refusing no-editor; the tools that truly need an editor (asset.reprocess, asset.ruler, entity.align, entity.fit_proxies) say to call editor.start."}
- {"area":"agent","text":"Your AI can now add a car or kart in one go. Adding the body and then its wheels was refused at every step (a vehicle needs wheels, a wheel needs its body), and the error did not say how to get past it. entity.add now takes the wheels in the same call (children), and the refusal says how."}
- {"area":"agent","text":"export.run now works on exports made with an installed engine: a release build has no query API, so the tool runs the exported game once through its own self-test and reports its frames, screens, script errors and first frame instead of failing with \"exited before it served\"."}
- {"area":"agent","text":"An export.run game kept running for more than 30 seconds lost its headless session: nothing reported for it, so the workspace service recorded it interrupted and stopped counting it against the machine's capacity. Its session now reports every 5 seconds, naming the game's process, so it stays admitted while the game runs and ends when the game does; and a crashed engine or game that has not been reaped yet now counts as gone."}
- {"area":"agent","text":"The feel probes now judge games they were not built on: response and movement wait for the controls to be live after a start countdown, a kart that hits a wall mid-steer is no longer called steered the wrong way, a side-on platformer is pressed along its plane (and no longer reads dead after the goal walk), a jump buffer or coyote time a game does not have reads 0 instead of unmeasured, brake distance and steer rate are read for karts that brake into reverse or hit a wall, buttons that need speed or a held item are not called dead, wall bumps count as impacts, a probe with warnings only is warn rather than fail, and a project outside the checkout finds the UI package."}
- {"area":"agent","text":"Feel probes: a camera lock-on's orbit is reported as movement.lockOrbitDegS and no longer judged as the body's turn rate; movement reads footSlideMs and facingTravelMismatchDeg per travel direction against facing (forward, strafe, back) so a forward walk clip played sideways or backwards fails the melee-duel and third-person-action profiles; the controls probe no longer calls a slow walker dead; one blow that re-touches its victim is one impact; unmeasured profile rows are re-run by the loop and role rows are labelled; the actions trace covers a 1.8 s heavy and an opponent that holds at the start is watched (and approached) for its telegraph"}
- {"area":"agent","text":"Feel tools: a model facing +Z reads forward/back right, the loop takes fresh probe values from the verdict, a hit window split by hit-stop and a re-touched impact are one, a player killed mid-probe is feel/player-died-in-probe, levers name the animator layer and controller rates; ctx.animator.speed accepts a negative value (plays backwards)."}
- {"area":"agent","text":"
foliage.presetno longer writes a foliage layer with more than 32 prototypes, whichcritic.checkrefused asschema-shaperight after the tool said ok: a preset with more plants splits into several layers (fp-<preset>,fp-<preset>-layer-2, ...) of at most 32 each, in order, with the same placements."} - {"area":"agent","text":"A dry run of generating a model from a chosen concept now shows the request and price of the route the real call takes (image-to-3D, or multiview for several views) instead of the text route. Tripo's P2 image-to-3D price is now 110 credits ($1.10), confirmed by live calls; the multiview price is still marked unconfirmed. Concept images made through Tripo now wait out its rate limit for about two minutes (including the limit Tripo reports inside a normal answer) instead of failing after 15 seconds when several are made at once; a refused call is not billed. A server error (502 or 503) is still retried only 4 times, since the task may already exist."}
- {"area":"agent","text":"The spend guard now checks every paid step of a generation, with what the call has already spent: before, only the first step was checked, so a reference picture could pass and the 3D step after it go over the cap unchecked.
generatetakesmaxUsd, a hard cap for one call (it was silently ignored before). A project that turns off \"ask before each paid step\" must set a spend cap; with neither, nothing paid runs. Tripo 3D calls now wait out a rate limit for about two minutes; server errors keep their shorter retry, since the task may already exist."} - {"area":"agent","text":"critic.play on an installed editor found no engine and answered tool-missing unless ARGUS_BIN was set: the installed argus, which serves the query API, was judged a release build because it carries the agent and the export composer, and both held the very sentence a release engine prints. The sentence is now looked for without being stored as itself, and only an engine built without serve carries it."}
- {"area":"agent","text":"Jettied houses (building.generate jetty, fit.rows.jetties) look right from every side: on kits that build roofs from small pieces, the roof now follows the jettied upper storey even when the gable faces the street, and the underside of the overhang is closed with the kit's floor where the kit has no jetty caps, so you no longer see into the house through a dark slot under the upper storey. Jettied houses built before look slightly different when rebuilt."}
- {"area":"agent","text":"Library search no longer counts noise as matches: a match far below the best one is cut (so the total is of real matches), the typo pass compares exact letter triples between words of like length (\"kit\" no longer meets \"1\", nor \"banner\" a \"Cornerinner\"), and a word's taxonomy value lends only the words that name a value themselves (\"stone\" no longer finds every \"Medium\")."}
- {"area":"agent","text":"play.input on a paused (stepped) Play waits through about a third of the editor frames it did (11 instead of 29 for a drive axis), so steering a game a tick at a time no longer costs seconds a press on a software renderer; what the game sees is unchanged."}
- {"area":"agent","text":"play.input presses an action bound only to a mouse button (and, in an agent's own Play, one bound only to a gamepad button or touch region) instead of refusing it for having no key, and moves a mouse-delta action such as look by pixels with \"mouse\": [dx, dy]; an action bound to nothing is still refused."}
- {"area":"agent","text":"The playtester no longer closes a game's results screen with Escape when the run has just ended at the last goal. A results screen that Escape closes (and that sends the game back to its title) made a finished run read as a fall out of the world; it now counts as the run ending where the game says it ended."}
- {"area":"agent","text":"The playtester now plays games with no walking player, such as a board or cursor game: it presses each action the game declares, compares the result with pressing nothing, and reports which actions changed the game. Before, such a game failed at once with play/no-player. The play command's new --kind option chooses the driver."}
- {"area":"agent","text":"The playtester now follows a game's menus into play: when the title has no one to play, it gets past the title and any picker after it, then walks, drives or explores whoever the race or level brings in, reading that scene's own controls. A player with no goals has its controls explored instead of passing untested. Other racers' bumps and pickups no longer count as the player's hits, and the interaction check no longer runs after the game has ended."}
- {"area":"agent","text":"The feel probes put the game back into play before every trial: a screen that came up during an earlier probe (a round over, a game over, a pause) survived the snapshot restore, held the world, and the actions and impact probes pressed into it (86 ticks, 0 events) when the camera probe ran first. Asking for the camera probe no longer changes the actions verdict."}
- {"area":"agent","text":"A town built along a race track no longer puts houses and trees on the track. The town tools (parcels.subdivide and dress) used to keep clear of their own streets only, so a kart track laid through a town had buildings standing on its corners. Now they keep clear of every road in the scene, out to its barriers."}
- {"area":"agent","text":"The feel probes' first wait for live controls no longer leaves the player where its held-forward look walked it: every trial starts from the restored start of play whichever probes ran first, so a punch at a post one metre ahead no longer raises feel/action-out-of-reach when only the actions probe runs."}
- {"area":"agent","text":"explain.search ranks the driving recipe and turnTowards in the top three again for \"driving game\" and \"face the player\"."}
- {"area":"agent","text":"Saving a material or shader, rendering a view and writing a terrain change no longer write through one temporary file name shared by every thread: two saves of the same file at once could fail with \"No such file\", one renaming the other's temporary file away. Each save now has a temporary name of its own, retries a refused rename on Windows, and removes its temporary file when it fails."}
- {"area":"agent","text":"When a play.query answer of events is too large and comes back as a summary, each event row now keeps a shortened payload, so a scene-load-failed event still shows its scene, code and reason."}
- {"area":"agent","text":"Talos tools connected for Claude Code inside WSL now start in a long-lived WSL terminal (tmux, say) whose link to Windows has gone stale: the server switches to a working link by itself, and when there is none it says to open a new WSL terminal or run wsl --shutdown. Connect again (Open with AI, or --connect-ai --client wsl) to get the new entry."}
- {"area":"api","text":"
entity.set(\"material\", { baseColor })now multiplies the mesh's owncolorinstead of replacing it, so white leaves an entity as authored."} - {"area":"api","text":"The POST /ui/* routes (push, pop, activate, focus, input, theme, scale, locale, viewport) answer after the state they made is laid out and published, so a GET /ui sent straight after reads it; before, a read could still be the tree from before the write until the engine's next publish (most often on a paused or loaded engine)."}
- {"area":"launcher","text":"The animation converter no longer drops the head, hands and toes of FBX rigs without end-marker bones, keeps every foot point (ankle and toe) at or above its rest height instead of only the ankle, and refuses NaN or infinite keys, left/right swapped bone maps and duplicate bone names with a message naming the bone and frame (--repair and --allow-side-swap override). It also warns about missing optional bones and forearm twist over 120 degrees."}
- {"area":"launcher","text":"Hop Lane's game over screen has a Menu button, and Esc there goes back to the title screen, where Quit is; before, Restart was the only way on and the window's close button the only way out."}
- {"area":"launcher","text":"Long project names stay inside their card, cut with an ellipsis; hovering the card shows the whole name, its folder and its note."}
- {"area":"launcher","text":"Launcher 1.0.4: an engine is never removed without being asked. Update says the build it replaces goes once the new one has opened, and the launcher says when it goes; Install and keep leaves both. A project's engine badge offers Switch project to… for newer versions too, and switches for real when nothing needs converting (Upgrade to… only showed a report)"}
- {"area":"launcher","text":"The New project page fits at 200 % display scale when a project type has more templates than fit in one row: the template cards wrap onto a second row instead of pushing the Name and Location fields off the right of the window. With room for one row, the page looks as before."}
- {"area":"launcher","text":"A launcher with nothing stored (not signed in, no tester token) no longer says a tester token was refused: it says the build is private and to sign in with the account your invite was sent to, or paste a tester token. A token that was sent and refused keeps its own message."}
- {"area":"launcher","text":"Start here's Play step is done once you have played your game, not as soon as the editor opens it. The editor records your own Play (F5 or the toolbar) in the project's state folder (editor/played.json); a Play a tool or script starts does not count."}
- {"area":"launcher","text":"Maximising or restoring the launcher window shows the finished layout straight away, instead of a stretched or half-laid-out one until the mouse moves."}
- {"area":"launcher","text":"The bug-report review now takes the page, My reports without an access token says what the statuses wait for (not a warning), Settings stops repeating the mirror line, and a bottom note goes when you change page (errors stay; Repair with nothing to fix says \"nothing needed repair\"). Every installed sample says where it is, and its install question no longer repeats the card's licence line."}
- {"area":"launcher","text":"Signing in with an account that has no invite is said in the launcher at once (\"The account you signed in with in the browser has no invite yet…\") instead of after the code runs out 15 minutes later; the code stays open for the invited account. The browser keeps the way back to the code. It needs the matching change on the accounts service; until that is live, the launcher waits as before."}
- {"area":"launcher","text":"On Windows, Sign in opens the sign-in page in your browser. Before, it could open your Documents folder instead and never reach the page. While it waits, the launcher shows the sign-in link with a Copy link button, so you can paste it into a browser yourself if no page opens."}
- {"area":"launcher","text":"The launcher offers Sign in at the top of Projects, where it opens, when nothing is stored to sign in with (it was only on Engine and Settings); a sign-in started there shows its code there. After signing in it names the organization as well as the email."}
- {"area":"launcher","text":"At its opening size on a scaled display (1040x700 pixels at 125%), the launcher no longer cuts off text: the first-run usage question's buttons and the \"no engine\" strip's button wrap instead of running off the page and widening it, and the window cannot be made smaller than 800x560 points, the size every page is checked at."}
- {"area":"launcher","text":"When the download server refuses for the terms, the launcher says what to do: review and accept them in the box it shows, then try the download again, and after Accept it says to try again. If your account already has the current terms, it says the problem is on our side, to try again in a few minutes, and to reply to your invite email if it keeps happening, instead of asking you to accept terms there is nothing to accept."}
- {"area":"launcher","text":"The Library no longer shows the same project twice when the projects folder is written with forward slashes, and a sample install that was interrupted no longer leaves a half-finished project card."}
- {"area":"launcher","text":"On Linux, uninstalling the last engine version also removes the engine's cache (~/.cache/argus: shader caches and unpacked tools) and the empty engines folder, and says which folders it keeps (saves, crash reports and logs)."}
- {"area":"launcher","text":"The launcher's Engine page opens the guides installed with a release that has no online documentation, instead of saying there is none; right after an install it no longer shows a Last checked time from before the install; and a sample for an engine that isn't released yet says so, with no Go to Engine button that leads nowhere"}
- {"area":"launcher","text":"Pebblewind Heights stays within its own triangle budget (now 200,000) now that built-in spheres are counted as drawn, so opening it shows no over-budget warning."}
- {"area":"launcher","text":"Esc (or the pad's B) on Hop Lane's game over screen and on Lantern Hollow's and Pebblewind Heights' results screens goes back to the title in a real window, as it already did in tests: the screens are dismissible now, so the screen stack no longer keeps the key from the game."}
- {"area":"launcher","text":"Start here's Play step now turns Done only once the editor has really opened a project, not as soon as the launcher started it; an editor that closed at once no longer counts."}
- {"area":"launcher","text":"Open with AI now shows a line for each terminal that works with any folder name (spaces, $, apostrophes, accents): PowerShell and Command Prompt each get their own, with a Copy button, and neither starts Claude Code in the wrong folder if the folder is not found. If you once answered No to the Talos tools in Claude Code, connecting undoes that. If Claude Code is not installed, the dialog says so and links to its install page. The config now names the installed launcher instead of whichever copy you ran it from, and says so when only a loose copy exists. Start here counts your AI as connected only when the launcher the config names is still there, and a .mcp.json or settings file saved with a byte order mark is read instead of refused."}
- {"area":"launcher","text":"After Send, Report a bug now shows a clear confirmation: sent, saved on this PC to send later (an install with no access token is no longer an error), or not accepted, with a short reference id you can copy, what was in the report, and where it went; the editor's confirmation says the same, and a report that cannot reach Cadarn's report server no longer blames the update server."}
- {"area":"launcher","text":"A bug report's log now hides your user name and every project folder however the path is written (any capitals, forward slashes, or from WSL), not only the projects currently shown."}
- {"area":"launcher","text":"A bug report sent from the editor now names the Launcher version that started it; every report used to say Launcher 0.0.0. The Launcher passes its version to the programs it starts, and an editor started some other way still says 0.0.0."}
- {"area":"launcher","text":"Request a feature opens a form with its own title and question, not the Report a bug wording."}
- {"area":"launcher","text":"Open with AI names the project as its card does, and says Claude Code first asks whether you trust the folder. A Verify that finds damaged files takes away the engine's green Verified badge until a clean check."}
- {"area":"launcher","text":"A sample's card on the Samples page now says which version is installed on your computer, instead of showing the version the list offers as if it were installed."}
- {"area":"launcher","text":"An installed sample on the Samples page shows one status and one Open button instead of repeating itself."}
- {"area":"launcher","text":"Lantern Hollow's and Pebblewind Heights' pause screens have a Menu button that goes back to the title screen, where Quit is; Esc still closes the pause screen and returns to the game."}
- {"area":"launcher","text":"A sample you install from the launcher already remembers its engine version, so opening it no longer asks to record one."}
- {"area":"launcher","text":"Lantern Hollow's and Pebblewind Heights' results screens have a Menu button, and Esc there goes back to the title screen, where Quit is, as in Hop Lane."}
- {"area":"launcher","text":"The samples' AGENTS.md no longer names a folder on the PC they were made on; your AI finds the engine's docs from the general rule instead. The samples' agent instructions now match a new project's, including how to connect from WSL and the scripted
claude -pline."} - {"area":"launcher","text":"The Samples page no longer shows a raw error. With nothing published yet it says \"No samples yet\" and offers Check again; when the download server can't be reached it says samples need an internet connection and offers Retry, with the technical message under Details."}
- {"area":"launcher","text":"A sample you install now shows on the Projects page straight away, and \"Open a sample or make a project\" on Start here counts it as done."}
- {"area":"launcher","text":"Start here now marks Connect your AI as done after you connect from a WSL terminal."}
- {"area":"launcher","text":"Start here and the guide say \"press Export\" where the editor's toolbar button reads \"Export\" (they said \"Export…\"), the Export step turns Done once a game has been exported to the project's dist folder, and the Play step names the project as its card does instead of its folder name."}
- {"area":"launcher","text":"The Start here button and the left-hand Start here item are no longer highlighted while the Report a bug or Request a feature form is open over that page."}
- {"area":"launcher","text":"Start here no longer counts or offers a project whose folder you deleted by hand. What's new says why it is empty when you are offline and offers Try again, and the Samples page shows an installed sample as Installed with an Open button after a restart."}
- {"area":"launcher","text":"The Install the engine button on Start here now starts the install instead of only opening the Engine page."}
- {"area":"launcher","text":"A Windows engine built without --esbuild fetches the win32-x64 esbuild at the version the checkout uses, as the nightly does, instead of stopping because a pnpm install from WSL has no esbuild.exe."}
- {"area":"launcher","text":"A Windows engine built without --win-node ships the pinned Node.js (v22.17.1, checked against nodejs.org's SHASUMS256), as the nightly does, instead of whatever Node the build machine has; its third-party notices describe that Node."}
- {"area":"docs","text":"Docs site: a guide's link to the script API (docs/API.md) opens the Script API section; it opened the query API guide, which shares the file name"}
- {"area":"docs","text":"The step-02 status notes no longer say world-space labels (
ctx.labels) are \"recorded, not acted on\": they say the labels are drawn, and cite the test that renders one."} - {"area":"docs","text":"INSTALL.md's crash-path check works on a Talos Launcher install (engines\\<version>\\bin), not only the MSI layout."}
- {"area":"docs","text":"The third-party notices no longer name where the HD sources were cloned on a developer's machine (~/argus-coord/hd/...); a test keeps any NOTICE.md from naming a home or internal path."}
removed
- {"area":"launcher","text":"The launcher no longer carries a Roadmap page: the roadmap will be on the Talos website, and Help > Roadmap opens it there once the site is live. The launcher is about 120 KB smaller."}