Spawn
spawn / swhat we're building

pinned

start herewhat spawn isfaqfrequently asked questionsthe betthe spawn bet

updates

engine v5.2Lume5 daysengine v5.1Connection3 weeksengine v5.0For RealJune 4, 2026engine v4.6AtelierJune 1, 2026engine v4.5Surface TensionMay 22, 2026engine v4.4SolidMay 15, 2026engine v4.3GroovyMay 13, 2026engine v4.2ContinuumMay 9, 2026engine v4.1FoundationsMay 4, 2026engine v0.1GenesisApril 29, 2026

pinned

what spawn isstart herefrequently asked questionsfaqthe spawn betthe bet

updates

Lumeengine v5.25 daysConnectionengine v5.13 weeksFor Realengine v5.0June 4, 2026Atelierengine v4.6June 1, 2026Surface Tensionengine v4.5May 22, 2026Solidengine v4.4May 15, 2026Groovyengine v4.3May 13, 2026Continuumengine v4.2May 9, 2026Foundationsengine v4.1May 4, 2026Genesisengine v0.1April 29, 2026
← All posts
← All posts

engine v5.2.3

Engine v5.2.3

July 15, 2026

A patch in the Lume line.

what's new

  • Fixed god mode getting stuck at an invisible floor in games with terrain turned off — you can now fly down to builds below height 0 instead of being silently held at the old ground level.
  • Fixed characters sometimes staying squashed after a fall — the un-squash now always completes, even on slower devices.
  • Recoloring or retexturing your terrain no longer hitches the whole game — tint and texture changes now apply in a blink (roughly 10× faster) instead of quietly rebuilding the entire landscape each time.
  • Retro pixel looks are razor sharp again. If your game renders at a chunky low resolution on purpose (PS1/N64 vibes), you get crisp pixel stairs back instead of the smoothed-soft image the new renderer's anti-aliasing was giving you.
  • Savi learned professional 3D tooling — she can now build game assets in Blender 5 (scattering, fracturing, tree generators, UV cleanup and more) and checks her own renders before the art lands in your game.
  • Rivers, ponds, and oceans can now wear fully custom looks — Savi can write a shader just for your liquid (glowing lava, cartoon water, murky swamp) instead of only styling the built-in water presets.
  • Art your game draws in code now works in your HUD and menus too — the same textures your scripts paint can show up as images in game UI.
  • The game quiets itself while you record a voice message, so your words come through clean instead of competing with your own soundtrack.
  • Sun shadows got cheaper while the camera moves — big outdoor scenes now spend noticeably less GPU drawing the same shadows, which means more headroom for everything else.
  • Animated art your game draws in code now animates in menus and HUDs too — a flickering torch or spinning coin painted by a script plays in your game UI the same way it plays in the world (it used to show only the first frame).
  • When one broken model spawns in lots of copies, you and Savi now get ONE clear error naming the model instead of a flood of identical errors — the flood used to bury the actual problem.
  • Trying to remove a player's custom look could silently bring their profile avatar back — it looked like the removal failed. Savi now gets told exactly what happened and how to actually clear it.
  • Savi edits game files with sharper, more reliable tools — fewer fumbled edits and clearer errors when a change doesn't land.
  • Savi can now restyle the parts of a 3D model separately — glowing brake lights on a car, a marble fountain with brass spouts, a new texture on just the roof — by naming the model's built-in parts. No model re-export, and it works on animated characters too.
  • Removing a mod now checks that nothing in your game still depends on its files first. If something does, you get a clear list of what to fix instead of a broken game.
  • Fixed multiplayer worlds sometimes refusing to spawn things for several seconds (or minutes) after someone alt-tabbed or hit a network blip — the world's host no longer loses its seat over a moment of turbulence.
  • Savi can now keep track of the walls, boxes, and props she builds with her quick shortcuts — hide-and-reveal effects (like roofs that peel away indoors) and interactive doors work reliably instead of silently losing track of pieces.
  • Savi builds better platformers on the first try — players standing on moving platforms now ride them smoothly instead of sliding off or overshooting at the turnaround.
  • Savi can now offer a "craft pass" on a part of your game that's grown messy from lots of small changes — same behavior, sturdier bones — and she'll tell you honestly when it's not needed.
  • Spawn something and use it right away — it just works now. Shots that fire the instant they spawn, portals that teleport on creation, chains of spawns acting on each other: no more "entity does not exist on the server" errors, and no need for little delays before acting.
  • Objects wearing legacy or unsupported materials now show up with a plain fallback look instead of turning invisible, and Savi is told exactly which object and material need re-authoring.
  • Grass, flowers, and terrain decorations now appear smoothly instead of popping at nearby distance bands, while using much less graphics memory.
  • Decoration slope and height rules plus clear-scatter zones now work consistently, and sprite decorations can use cropped texture regions with custom ground anchors.
  • Overlapping pixel-art trees and props now keep the correct front-to-back order as the camera moves.
  • Sound effects no longer crackle or pop when several loud loops play at once or when your scripts fade volumes and pitches every tick — loud mixes are caught by a safety limiter and volume changes glide instead of stepping.
  • Switching to another tab no longer makes the engine think your game is running slowly — no more false low-framerate alerts to Savi or your custom materials getting paused while you're away.
  • Your game can always tell who the current player is: the player's account id is now consistent across every script surface, in singleplayer too — no more empty ids that made per-player saves unreliable.
  • Fast-travel and portal trips no longer leave screen effects stuck on: temporary looks (like a warp overlay) and camera lens changes (like a widened FOV) from the previous place release automatically when you arrive, instead of persisting until a refresh.
  • A script bug that produces an invalid camera FOV can no longer permanently warp the view — the camera holds its last good lens and the problem is named in the logs.
›technical notes
  • God mode no longer enforces a phantom terrain floor at y=0 in terrain-off games (ledger #1329, dump dd9ad1f0). The god-mode behavior duplicated the spec-side terrain predicate (spec.places[placeId]?.terrain !== undefined) which counted terrain: { kind: "off" } as terrain-on, while the interpreter removes the world terrain definition for kind:"off" — so getTerrainHeight returned 0 and the per-tick clamp snapped god-entity feet to y=0 forever (entry teleported the creator up; fly-mode descend netted zero every tick via same-tick snap-back; ascend still worked because the clamp only pushes up). The duplicate predicate is deleted: the behavior now derives terrain-liveness from the world's installed definitions via hasTerrain(world, placeId) (engine/features/terrain/alignment.ts), the same predicate every terrain system uses. Terrain-off (and failed-generator) places now take the designed no-terrain branch: parked hover in walk mode, free flight below y=0. Real-terrain places keep the clamp exactly as before. Pinned in no-terrain-floor.test.ts (entry below y=0, fly-descend across y=0, walk-mode park, real-terrain clamp control).
  • Presentation motion-juice restore is convergent instead of one-shot (ledger #1316, dig bda7b9f7). The squash/shake deformation channel (draw/motion-juice) refreshed per client frame while live but relied on exactly one component-REMOVE-triggered restore frame — and that REMOVE rides a droppable render-channel hop (frame decode failure, lost string refs, stream-reset snapshots that re-encode only still-live components). On degraded clients (quality ladder 5/5, halfRate, frame-budget fallback, tab supersession) a lost REMOVE left the composer's MotionJuiceState stale forever, recomposing the crushed pose over every later authoritative scale write — invisible to script-side scale guards because authoritative WorldScale was never wrong (presentation-only by design, ledger #951, unchanged). The composer now holds each deformation under a liveness lease (MOTION_JUICE_LEASE_MS, 1s of display time, renewed by every ingest): when the refresh stream goes silent without an ending frame, the deformation expires and the drawn pose converges to identity through the existing restore paths. Zero cost for entities without live deformation. Pinned in synthetic-transform-motion-juice.test.ts (lost-REMOVE squash/shake/hierarchy-child convergence + refresh-keeps-alive).
  • Shading-only terrain-materials fast path (#9171, ledger 1324): a materials delta that changes only shading fields (tint/color, texture refs, tile/textureScale, metalness, normal/roughness params) now swaps the material pack into the installed terrain definition in place instead of flipping the definition revision — the revision derives from a STRUCTURAL signature (material ids/order + generator source/deps + marks + seed + rooms — everything chunk builds and colliders actually consume), so a tint-class patchTerrain pays no whole-place reinstall, no dirty marks, no collider-readiness churn, no spec re-expansion or anchor/scatter refresh. The renderer re-reads the swapped pack through the existing per-place TerrainPlaceRenderConfig channel (content-hash deduped). Measured on the ledger-1323 driver's tint-tick phase: 220.06ms mean / 256.75ms max per call (20/20 ticks spiked) → 18.58ms mean / 26.53ms max, zero spikes. Structural changes and validation failures fall through to the full reinstall byte-identically.
  • Aesthetic-band renderResolution ceilings render raw pixels again (#9158, ledger 1322 — enfeul's First Light). Since 5.2.0 made TAAU the sole 3D production AA mode, games with an authored engine.graphics.renderResolution ceiling (the PS1/N64 look) went soft — Halton jitter + temporal history erase exactly the aliased stairs the look is made of. An authored ceiling with short axis ≤ 480 now declares raw-pixels intent: those 3D frames run the msaa topology (no jitter, no history, direct composite — the same production lane 2D scenes run), and the governor's renderScale rungs become inapplicable there, so nothing ever renders below the authored ceiling. Above-band ceilings (540/720/900/1080 — the perf-cap population) stay perf caps on TAAU; the authored↔unauthored edge invalidates TAAU history like the 2D↔3D cut. No new spec surface.
  • Savi's Blender-5 game-asset system (#9187): the blender-game-assets skill (hidden, runtime: chat) teaches natives-first professional 3D asset work — Blender 5.0 geometry-nodes scatter modifiers and SDF grid damage, 5.1 dilate/erode — over a vetted addon short-stack (BagaPie, Cell Fracture, Modular Tree, Mio3 UV, UniV) in the bpy dialect (append node groups, enable addons in-script), with game-ready export truths and a render-verify loop. Workshop upload lines become exact-URL read grants, so Savi can view her own rendered proofs the moment their URL prints. The savi-workshop image bumps Blender 4.2.22 → 5.1.2 alongside (companion-side), with an idempotent provisioning script for the vetted stack.
  • Scripted liquid shaders on terrain marks (#8749, plan p-520aae28): LiquidSpec.material?: ScriptedMaterialSpec — a river/pond/ocean mark's liquid can reference a Savi-authored scripted material, the exact { kind: "scripted", script, params } shape objects use. kind stays the substance (physics/audio/particles); material is look-only and replaces the whole liquid visual while the declarative knobs style the fallback. Attach/detach/param edits rebuild surfaces (the interpreter's liquid signature carries script + params), scripted refs on marks (top-level + every place) reach the renderer's material library, a parked/unclaimed scripted Water/Surface bespoke routes onto the water preset look (never the grey vertex-PBR lanes), scripted claims pass params only and keep castShadow false, and patchTerrain refuses a liquid.material.script that doesn't resolve.
  • scripts/ texture refs resolve as game-UI image sources (#9154): ui.js HTML now accepts texture-script refs in img src and style url() — the dom-host substitutes the baked blob URL (transparent placeholder until the bake lands, never a broken glyph), bakes ride a renderer-host RPC on the existing bake transport (same compile cache, budget rails, and park diagnostics as world bakes), and setTextureScriptLibrary's changed/retired delta re-bakes changed families live and revokes stale blob URLs. The drawn-art skill's HUD ban drops — the taught exception this deletes.
  • Game output ducks while the voice recorder holds the mic (#9152): speaker output ducks to 15% over a 50ms ramp while kiln's recorder is live, restoring over 200ms on release — game audio bled into the mic and poisoned voice-message transcription.
  • Per-cascade sun-shadow GPU culling (#9163, slices 1+2 of the moving-frame shadow plan): shadow select joins the lume GPU cull as a fourth variant classifying by occupancy + 6-plane cascade box only (no maxDistance, no LOD pKeep, no ring — the contract is "current set minus outside-the-box"), with per-cascade cull cameras, args ranges, and survivor buffers sharing group data with the main view, dispatched only for scheduled cascades whose view is dirty. Receipts (Apple M-series): cool-basis sun-cascade GPU −45% on the moving-frame bench, net −8.7% GPU on the valley pack at realistic load (dpr-3), GPU power −13% / energy −11%. Ships with the bench-shadow-moving rail: an always-orbiting UGC-shaped caster fixture and occurrence-correct per-pass windows (amortized cost over all frames, not just when-present means).
  • Internal/observability: the 5.2.0→5.2.2 tick-budget attribution dossier + full-stack A/B tick profiler (#9184, dig 47285eae); server_behind episode payloads carry room load counts + egress stage means (#9174, ledger 1326); netcode-egress bench TomeWorldReplicated registry fix + specimen-1326 config (#9173); perf-capture rig mutes audio by default (#9169); engine-version tooling's r2Read downloads via temp file — the prod catalog outgrew execSync's 1MB maxBuffer (#9147, ledger 1318).
  • Animated texture scripts play in game-UI imgs (#9222, the #9154 follow-on): an atlas bake that declares fps (ctx.atlas or the meta export — the same declaration a bare sprite plays world-side) now animates in ui.js HTML. The one deterministic bake additionally slices its default clip into per-frame PNG blobs renderer-side (off the page main thread), and the img lane ticks tracked <img> srcs between pre-made blob URLs — nothing re-bakes per frame, and the requestReapply pipeline stays first-arrival/invalidation only. Rails: declared fps clamps to 10 UI-side; 8 concurrently animated refs (overflow holds frame 0 + one loud fault on the ui-fault rail); 64 frames per clip (over-cap serves the still sheet + one renderer diagnostic, re-keyed on clip length so an edit re-reports). Ticking starts on fragment substitution, stops on the first tick with no live element, dies with dispose; zero timers for games with no animated refs.
  • Costume-keyed diagnostic emitters re-keyed to their CONDITION (#9228, the Shimmerwilds storm — 132 emissions in 90 min from one boneless model): model-not-animatable and the model-clip warns key on the MODEL (model-not-animatable:${modelId}, ref-only-key doctrine), entity id demoted to the data payload, so a population spawner minting fresh entity ids no longer turns one broken asset into an unbounded error-DM storm — the existing key#contentSignature dedupe collapses it to ≤1 admitted log entry per broken model per window and one hidden Savi turn. Transient sprite-atlas warns re-keyed per BASE in the same pass.
  • Authored-clip bind problems re-keyed per MODEL (#9237, same class): reportAuthoredClipProblems' three bind codes keyed (and worded) per entity; now keyed on state.modelId with the entity in the payload/console line only. The cap wraps the assembled variable suffix via diagnosticKeyRef at 172 chars so the longest prefix still fits MAX_KEY_LENGTH. Also fixes a stale physicsEngine-default comment.
  • New warn when a player-model clear resolves to the profile-avatar fallback (#9242, dig d3f2d32c — the removal that summons the thing): patchPlayer({properties:{model:null}}) is exactly ledger 936's fallback trigger, so Savi's removal verb re-summoned an avatar while her verification read honest nulls. warnPlayerAvatarFallbackRedress fires at the write transition only (setObjectProperty seam + patchPlayer/applySpec diff seam, gated on prev-template-had-body → next-template-bare — never ambient spawn-time, where account avatars are the legitimate normal), keyed per player per the #9228 convention, and the message teaches the cure (animated3DCharacter:false on the player template, plus that already-joined sessions keep the old body).
  • removed-api-tombstones grows 5 entries feeding the new chat-side draft-gate lint (#9200): tombstoned/phantom api calls are blocked at Savi's write time with the teaching error, before a broken script ever reaches the engine.
  • Savi's file tool surface renamed from the command-enum str_replace_editor to Claude Code-shaped Read/Write/Edit/Delete tools. Engine-side teaching text follows: skill sources (drawn-art, creator-ui, custom-materials, 3d-sprites, 2d-mode, workshop) and the runtime diagnostics that steer toward file creation (scripted material/texture/look script-not-found errors, the ObjectAPI memory side-door rejection) now name the Write/Edit tools. Rooms pinned to older engine versions keep the old steering text until this version reaches them; the live tool registry itself ships with the chat deploy, and a stale steer degrades to a recoverable unknown-tool error.
  • Material slots (#9213, plan p-04342ee6): model.materials — the object form paints PARTS of a model. Entries are keyed by the GLB's own material names (model: { id: "cdn/car.glb", materials: { BrakeLights: { emissive: "oklch(0.65 0.25 25)", emissiveIntensity: 4 } } }), mount Magic-CDN textures and packed PBR pairs onto named slots (materials: { marble: { texture: "cdn/texture-marble-white-veined.png", pbr: true } }), and are live-writable via setProperty("model.materials.marble.texture", …). Works on static and rigged (skinned) models; sharing is batch identity; swap-in follows the existing placeholder-then-swap law; a name that matches no material in the GLB reports instead of failing silently. Re-writing model without materials clears them. Savi's write-time PBR prewarm derives the packed pair for every material entry whose cdn raster texture and pbr flag share one object, so slot-mounted PBR doesn't cook on first client fetch.
  • Mod remove refuses while surviving scripts still require() the mod's files (#9261, badgerblunts/the-workshop 07-14): an uninstall deleted the mod's lib files in one write while ui.js + 3 other scripts still carried top-level require()s — ~3 minutes of [Tome] Module not compiled render failures until the dangling refs were cleaned by hand. remove now scans every surviving script's require()s (the adopt path's resolveRequireTarget, mirroring the kernel's caller-scoped resolution) against exactly the script keys the uninstall will delete; any ref that stops resolving refuses by default listing each dependent with its exact require, force: true removes anyway and reports the same list as a warning. Matches the family's safe-by-default shape.
  • Place-host assignment splits RETENTION from ELECTION (ledger #1327, dig efad3b28). isEligibleConnection — Streaming (or the never-streamed join window), attached, Ready — is the right bar for electing a NEW host (it must be able to take the make-before-break snapshot), but reconcilePlace used the same predicate to decide whether a SITTING host kept its TomePlaceHosts entry. Any transient transport boundary — the make-before-break NeedsReset its own assignment sets, a ws delivery-fail reset hold, a client self-heal reset, a hidden tab — fired the host the same tick, deleting the entry for an OCCUPIED place: every unowned create then rejected at the drain's table-stamp gate ("Tome spawn: place X is not resident"), the displaced host's in-flight writes died at the stale-epoch gate ("previous host epoch skipped"), and re-election at epoch+1 flipped NeedsReset again and cut another full-place snapshot into the same congested socket (a self-sustaining flap: 3 elections in 7s, then 10+ minutes unhosted, on live DD receipts). A sitting host now retains its entry — same clientId, same epoch — while its connection is Ready and attached, its PlaceMembership still names the place, it is not suspension-stamped past the takeover grace, it is not silent on both upload cadences past the existing health window, and it has not been off Streaming past the retention ceiling (HOST_NOT_STREAMING_RETENTION_CEILING_TICKS, 600 ticks ≈ 20s at the 30Hz default — the in-system bound for the heartbeats-pass/resets-fail backpressure wedge that input-frame health cannot see) (isRetainedSittingHost; no new timers, tick arithmetic only). Genuine session boundaries — detach, suspension-stamp, place-leave, disconnect, opt-out, sustained silence — revoke exactly as before, and election is unchanged (including ledger #1237's hostEligible: false gate).
  • All 34 builtin/primitives helpers return the spawned entity id (api.spawn's resolved return — parent/mod/place-qualified where applicable), enabling const roofId = p.box(...) capture for hide-lists, door registries, and destroy/patch calls. Previously the internal _spawn discarded the id. Skill teaching updated in the same change (the mangled-ids workaround is gone from the corpus).
  • platformer-movement skill teaches moving-platform carry as position-snap, never velocity-borrow (#9227, ledger 1341): riders inherit the platform's per-tick displacement by snapping with it, instead of borrowing platform velocity (which overshoots on direction changes and strands riders at endpoints).
  • Walk-independent iso-town teaching corrections from the eval (#9204): interactive-objects, structures, and 4 sibling skills correct the mis-teaches the iso-town eval surfaced.
  • New savi-craft skill (#9243, plan p-7074adc5): the creator-facing structural-rebuild pass behind the /skill command — find what's grown tangled through many small patches, map every behavior it carries, rebuild the minimal clean shape; honest no when the build is already sturdy. Includes the ambient-offer discipline (when to offer the rebuild unasked).
  • game-ui skill drops the desktop-only framing for Savi surfaces (#9220 — mobile is part of whole).
  • Spawn-then-act ordering contract: commands referencing a not-yet-known entity park server-side for a 3s create grace (a sim-tick window, stamped at first park and carried through re-parks — one window per command) and re-adjudicate through the full live authorization gate the tick the create lands, exactly as a network-delayed command would (generalizes the rail.destroy-only 1s park to entity-referencing commands; RAIL_DESTROY_GRACE_SECONDS deleted). Parks are bounded per client AND per room in count and bytes (oldest evicted loud at a room ceiling). The client's synthetic-create flush now walks TomeSpawnedBy ancestors, so same-tick spawn chains ship in program order. Commands referencing recently destroyed entities are dropped quietly via the despawn ledger instead of surfacing error DMs (client-uploaded despawns; entities destroyed by server-side commands still report with honest text until the ledger covers them — named follow-up); self-destroys whose create never arrived expire silently (the world already converged).
  • Batch-ineligible primitive materials (unknown/legacy material keys like "Scripted" without a script ref, wireframe, alphaTest, non-front side, unknown override keys, depthWrite:false while opaque) now draw a degraded Std/PBR fallback recipe instead of resolving a null representation — the 5.2.0 lume port skipped these classes to invisible (the three-era standalone mesh path drew them, deleted in #7602; #8830 fixed the pbr:true subclass, this covers the residue). The degraded resolve strips exactly the rejected bits and keeps every mappable param (color/map/tint/PBR scalars/transparency); flash appearance writes resolve through the same fallback.
  • The primitives-material-unsupported diagnostic now names the offending entity id and material key (or the exact offending override keys) in the message that reaches Savi's DM — the previous static generic text was unactionable (dig 9a59bc78: Savi answered "." to it or misattributed the invisibility to stale room state).
  • Rebuilt terrain decorations around compact 24-byte candidate records and 4-byte survivor refs, bytes-first adapter-limit admission, shared packed frustum culling, and live allocation-free quality uniforms. The measured desktop baseline requests 1.25× authored density across 1.75× distance; 3M candidates or the adapter's lower byte limit is a hard safety ceiling, while the default meadow builds about 1.07M. Tablet and phone remain unchanged.
  • Replaced hard near/mid/far population swaps with deterministic cumulative density strata and guarded root-collapse bands. Terrain tiles and newly ready sprite assets reveal through bounded birth ramps, wind/root transitions write real motion vectors, and stationary scenes return to zero decoration placement/cull work.
  • Decoration placement now honors authored slope/height ranges and terrain clear-scatter exclusions in addition to material, paint, noise, cluster, and water gates. Slopes use Spawn's normalized 0-flat to 1-vertical scale, with compatibility conversion for legacy degree values. Sprite decorations also accept normalized uvRect and anchor controls shared semantically with entity sprites.
  • Ground-cover is full through 175m on the measured desktop baseline and collapses to zero by 245m through a root transition. Cards grow modestly near the field rim to cover the remaining bare band without floating or scaling distant props.
  • Pixel-inferred 3D sprites such as Pixel Kart's trees again use depth-writing cutouts by default, eliminating camera-sensitive whole-batch ordering flips while explicit soft and linear sprites remain blended.
  • The SFX bus now routes through a DynamicsCompressor safety limiter into the master bus (ledger #1386) — the clip-voice mirror of the vibe sampler's safetyLimiter, same settings family (threshold −3dB, ratio 3:1, knee 8dB, attack 5ms, release 120ms). Script gains stay unclamped; stacked looping voices with gains >1 that previously summed past full scale and hard-clipped the destination (crackle/popping) now degrade gracefully through the limiter. Transparent on normal content: single voices at gain ≤1 sit below the −3dB threshold on the bus (and −9dB more headroom follows at the default master gain), so the limiter idles.
  • Clip-voice set-command updates (gain, pitch, reverb send) now land as an anchor plus 20ms linear ramp (CLIP_PARAM_RAMP_SEC) instead of instantaneous setValueAtTime steps — the same shape the vibe lane already used. Scripts that ease these params every tick no longer produce a waveform discontinuity per tick (zipper noise).
  • Also aboard from the jul-15 freight (merged without changesets): AOI rides the octree — per-tick O(world) egress scans are gone (#9210); lume slash-lane instance stride fix — CPU packed 256 B against the WGSL struct's 240 B (ledger 1306, #9292); the external-URL audio load-failure verdict tells the truth — no allowlist exists, live streams are a category error (#9298); cold-load 429s take a boot-window short-retry lane instead of the 5-minute tombstone park (ledger 1379, #9329); storage teach carries the user/<id>/ placement constraint in the server-context steer (ledger 1381, #9333); audio skill re-cut hook + AudioSpec breadcrumb so diegetic music asks route pre-load (#9339); wisp blender charters mechanically load blender-game-assets (#9330); spawn-then-act follow-up — #9251 review nits: name-based dispatch lookup, overflow-warn throttle, refs hygiene pin (#9343).

KNOWN OPEN (5.2.3 staging draft — minted 2026-07-14, sha last folded 2026-07-15 ~20:48Z with the jul-15 freight aboard; named honestly for the walk and the release packet; the draft:false flip is the train's separate human-gated step):

  • Ledger 1333 tick-budget hold — RESOLVED FALSE-READ, PROMOTE GATE LIFTED (2026-07-15): tucker's local bisect and a staging A/B canary agree — no regression rides this sha (the 3× read was an evolved-world comparison, "a poisoned test"); ledger 1333 closed as false-read, the #9026 suspect cleared. 5.2.3 promoted to prod 2026-07-15 (run 29464253946, green).
  • FrameBudgetGuard now treats hidden-tab time as non-evidence, in both hidden regimes. Throttled-flow (samples keep arriving ~1Hz): FrameBudgetSample.documentHidden (fed from the renderer worker's visibility state) takes the same early-return as the grace windows — flush the judged window, reset the fallback timers, drop the chronic span anchor. Fully-parked (no compositor begin-frames, zero samples): the visibility handler's hidden branch calls frameBudgetGuard.notePause() beside the governor's and hitch detector's, so a fallback timer armed by a pre-hide struggle can't bridge the gap and park instantly on the first post-return sample. A backgrounded tab's inflated presentedIntervalMs read as the idle-CPU GPU-bound shape (#199), so a few hidden minutes fired false frame-budget-warning chronic DMs to Savi and false fallback parks of scripted materials. The quality governor and hitch detector already kept this law; the guard was the one visibility-blind judge on the frame rail.
  • The visible edge of the visibility handler reseeds the renderer stats sampler (statsSampler.reset(), the same parked-tab-time law renderFrame's >2.5s loop-pause reseed keeps), so a short hidden gap or a throttled-flow tab's boundary window can never manufacture a gap-sized "presented interval" on return.
  • Player identity now resolves through one verified rail (resolvePlayerIdentity: server-populated TomePlayerProfilesResource, else owner-replicated SessionClient) on every surface — api.userId, getPlayers() (ObjectAPI, CameraAPI, and run_script exec), getProfile(), getUsername(). On client-simulated worlds (all behaviors in singleplayer; host-run world behaviors in multiplayer) the session's own player now reads the same real account id everywhere instead of null/"".
  • getProfile() no longer coins "" for unknown userIds and no longer parrots script-writable TomeState.userId as identity: PlayerProfile.userId is now optional — real where verified, absent where withheld. Other players' account ids stay off client worlds by design (SessionClient owner-only replication is unchanged); jsdoc + generated API reference now state that contract explicitly and route cross-player identity work to server context (lifecycle/cron).
  • Place-transition presentation reset (ledger 1387, dig 499c9122): duration-less api.pushLook layers — the one layer class with no scheduled end — are flagged clearOnPlaceTransition and begin their normal fade-out on spec-sync's placeChanged edge (client-side, netIngest, so destination arrival hooks that push layers land after the sweep). Duration'd pushes keep their armed cleanup timer; juice sugar layers stay engine-managed; atmosphere.look untouched.
  • enterPlace across places now removes the traveler's (and god mirror's) TomePlayerCameraOverride at the transfer — the session override previously persisted until session end, which parked a mid-ease setCamera({ fov }) on the player in the destination forever. applyPlaceSpawnRotation re-seeds the view direction after the clear; mint-transaction compensation restores the captured override exactly on rollback.
  • NaN guard on the renderer camera smoother's FOV chase: a non-finite ingested view.fov no longer poisons renderFov for the rest of the session (exponential filter memory) — the smoother holds the last finite fov, keeps rendering, and reports once through the engine-diagnostic rail (new log-only code camera-fov-nonfinite, visible in getLogs).