Saved drafts can now be applied to a shared development room from the atelier. The player stages its native simulation, a new presentation generation and GPU catalog before acknowledging readiness. The relay accepts the change only after every participating browser prepares; the editor distinguishes saved, preparing and live revisions. Published playtests remain immutable and continue using their existing routes.
#Prepare and swap
await simulation.prepareRevision(nextWorld) owns and validates the proposed world, compiles its assets/collision, checks compatibility and returns an immutable plan tied to that simulation. Compilation does not pause or mutate the active runtime. The plan exposes the next world/content and created, updated and removed authored entity IDs for resource preparation.
At a completed fixed-tick boundary, simulation.forkRevision(plan) captures the latest runtime state and synchronously creates a separate validated simulation. The original remains intact. A successful plan is consumed; forged, reused and disposed-source plans fail. Callers can then exchange the active reference and dispose the old runtime. A failed fork disposes its candidate and preserves the original.
The caller must prepare graphics resources before the exchange and start a fresh presentation generation afterward. Entity identities survive; consumers must rebuild store handles and projection baselines when exchanging runtimes. This API alone does not coordinate multiple clients or activate a room revision.
#Preserved state
The candidate retains the current player pose/velocity, pending input and age, tick, pause state, facing, event queue/cursor, scheduler, inventory/flags/doors, route clocks, NPC conversation state, shared equipment and admitted remote-actor rows. Authored component differences replace only the affected source-controlled values. Unrelated runtime components, including animation phase and spawned platforms, survive verbatim.
Physics is prepared from a native checkpoint clone. Purely visual changes keep the native snapshot unchanged. Collision topology changes rebuild static colliders in the clone and refresh native queries with zero elapsed time using the pinned Rapier runtime. Player and platform state must remain exactly equal; the adapter restores body velocities and rejects any discrepancy. The candidate must also fit the native checkpoint budget. Native static collider handles may change. Moving body state, platform targets, blocked state and rider support remain intact.
An activated collision topology may not penetrate the local player beyond the small contact tolerance. Invalid geometry, incompatible animation bindings and runtime/schema invariant failures also reject the candidate. The new simulation produces checkpoints pinned to its new content; old-content checkpoints cannot silently load against it.
#Current compatibility boundary
Existing-object transforms/materials/visibility, static object creation/removal, imported assets/collision and scene lighting can be prepared when compiler and runtime invariants pass. World identity, release and entry must remain the same. The set of places and existing story interaction identities remain fixed. Format-6 static object dialogue bindings may be added, moved with their object/group, edited or removed; they have no persistent gameplay effects. Removing a nearby binding clears its obsolete nearest prompt, while an already open dialogue can finish its retained pages. Existing dialogue prompts, speakers and pages can change; their reach, positions, conditions and effects stay fixed. Open conversations keep their current pages, while the next interaction reads the accepted text. NPC/route definitions require an explicit migration policy; their material can change while their live clock and state stay intact. This adapter targets the shipped built-in runtime profile; additional component/system contracts need an explicit migration path. Runtime asset references that disappear from the new catalog reject instead of resetting those entities.
The development integration keeps saved, prepared and applied revisions distinct. Physics and simulation swaps occur at a room activation barrier. A proposal rejected before durable acceptance retains the old runtime; an accepted decision is recovered from the room ledger and is never rolled back to a different room head.
#Development-room coordinator
With the editor enabled, POST /api/authoring/development accepts the exact saved baseRevision and baseHash under the existing editor-key and Origin checks. Selection runs in the draft commit queue. It does not publish an immutable playtest. GET on the same endpoint reports the active document and latest operation separately. The first application creates an independent development room; later applications propose revisions to its admitted players. Repeating an in-progress application of the same document returns the same operation.
The room uses /api/development/world, /api/development/session, /api/development/health and /room/development. Normal players use /api/development/content/manifest for the accepted head and pin /api/development/revisions/<document-sha256>/content for selected place/model downloads. The original full-document routes remain available to tools; active, proposed and retained historical snapshots allow offline saved journeys to migrate from their original content. The player selects these routes with /?development=1. Admission requires the explicit liveRevisions: 1 capability. The player advertises it only with its revision lifecycle hooks installed; older clients cannot silently participate without preparing native and GPU resources.
A proposal checks runtime compatibility and refuses to begin while gameplay intents remain pending. It captures at most eight connection incarnations, freezes gameplay writers and the shared route clock, and sends a unique preparation operation. New admissions are refused while the barrier is active; retry joining once the editor reports the revision live. Every participant must acknowledge readiness within 30 seconds. Rejection, a disconnect or timeout before acceptance aborts the proposal and retains the old content. Delayed acknowledgements from another operation or connection cannot satisfy the barrier.
The accepted document pointer, runtime content hash, next authority epoch and shared room state are persisted in one room.json transaction before a commit announcement. Each document is already durable in the room's separate immutable snapshot archive. Players then have ten seconds to acknowledge application. Connections that fail after acceptance are removed before writers reopen; the accepted revision is never rolled back. Development poses and intents carry the runtime content hash, and authority commits retain epoch fencing, so old-generation traffic cannot write after resumption.
openDevelopmentRelay recovers the document from that same room ledger, preserving sessions and shared state. An interrupted preparation restores the old document; an interrupted accepted revision restores the new one even if nobody received its announcement. The persisted route pause excludes barrier downtime on restart. Ambiguous storage failures latch the room closed until restart, including admission requests that were already reading their bodies. The development archive retains up to 1,024 snapshots within 256 MiB of stored history; see the lossless compaction policy below.
Coordinator acceptance uses real HTTP/WebSocket clients and temporary disk state. Browser acceptance separately exercises the actual editor and players, including an imported asset, changed collision, unsafe-overlap rejection, both graphics placements and saved-journey migration. See the browser acceptance record for the exact verified scenarios and remaining fault coverage.
#Try it locally
- Run
npm run dev:editoroncodex/engine-foundationsand open the private editor URL it prints. The existing editor preview useshttp://localhost:5181/editor.htmland retains its editor key. - In Shared room, choose Start shared room, then Join the room. Invite another browser or device using the same
/?development=1URL on your configured origin. - Move a static object in the atelier and choose Save changes. Saving alone leaves the running room unchanged.
- Choose Apply saved revision. Players briefly stop in place while the native and graphics candidates prepare. The card reports participant readiness, then the live revision. If an edit overlaps a player or cannot be prepared, it explains the rejection and keeps the previous world.
- Continue exploring. Try a solid object to verify the new collision, or leave one traveler offline while another edit is applied, then reopen the development room.
The development room owns .data/editor-ferry.1/development in the local editor launcher. It is separate from the original beta, garden preview, draft file and published rooms. Docker/Coolify deployments retain it under the existing relay data volume and use the same HTTP/WebSocket port. No new port or reverse-proxy route is required. Deploy the branch build before testing these controls on a hosted instance; this work does not deploy it automatically.
#Browser preparation and recovery
DevelopmentSession freezes stepping at a completed worker boundary while selected content downloads and compilation run. The session checks the proposed publication binding; prepareStreamedRevision then prepares only current-place/visible-window model payloads under a separate owner. The original simulation remains intact. The candidate projection begins above the previous exact presentation generation, including generations above 2^53. Both main-thread and worker graphics upload the proposed catalog and validate its complete scene against geometry, skin and instance budgets while keeping the old GPU scene. Abort disposes the candidate; commit installs the prepared scene/catalog and simulation. Existing transfer channels retain buffer ownership and request a fresh baseline after resumption. Input/menu changes received during the barrier are deferred until it ends.
Development local saves use a single envelope containing the document checksum and the lightweight player save. An offline reload opens that retained revision manifest, downloads its selected models, reconstructs its simulation, then uses the same state-preserving revision adapter to reach the current head. Native checkpoint recovery retains the original immutable manifest descriptor for the same migration. An interrupted live socket checks the accepted head and prepares it before reconnecting; permanent migration/graphics failures stop with the previous save kept instead of endlessly retrying incompatible state. Temporary relay unavailability backs off and retries.
The archive preserves offline source revisions through lossless compression. Broader device-loss/fault combinations, unlimited-history retention, long-session capacity and unrestricted gameplay/schema migrations remain unfinished roadmap work. Durable editor undo and published executable pinning have separate scoped acceptance. Character redesign remains deferred to the final polish pass.
#Lossless development history
The shared-room card reports retained revision count and stored MiB. Each complete source document is compressed to <sha256>.json.gz in the development room's revisions/ directory. Existing .json snapshots remain readable and compact automatically on the next update. Compaction preserves document identities, including revisions needed by offline local saves; it does not expire them by age.
New copies are written exclusively, synced, read back and checksum-validated, then renamed and directory-synced before the old file is removed. Interrupted upgrades may leave both formats, which are verified and reconciled on retry. Startup removes only matching regular temporary files; unsafe entries and corrupt source documents fail explicitly. Failed archive writes precede the room activation barrier, so they cannot activate a new world. Back up the entire development directory, including room.json and both snapshot formats.
The archive allows 1,024 unique snapshots and 256 MiB of stored history. Documents remain bounded to 16 MiB after decompression. A full archive rejects further additions while keeping existing revisions and the active room; applying an already retained snapshot remains possible. There is no automatic eviction, manual pruning interface, arbitrary engine migration, or guarantee of unlimited history. Published-world storage has its own separate policy.
To try it, start the editor and shared room, save and apply several edits, and watch the history line beneath Apply saved revision. Close a player's tab, apply further compatible edits, then reopen the development invitation in the same browser: its saved journey resumes against the current world. The browser regression exercises this across 36 updates, beyond the former 32-snapshot ceiling.