Status: architecture baseline; early cooperative playtest implemented. Date: October 24, 2026.
The current build is a narrow, trusted two-player playtest on the path to this architecture. See the implementation capability matrix and beta decisions for shipped behavior, temporary simplifications and evidence. The creator-preview requirements below still apply; this playtest does not complete that release gate.
Dusk is the engine described here. Darkwind is its reference game, built with Dusk; it is not the engine product. See Dusk compatibility for identifiers that keep the earlier name.
Build an independently implemented web game engine that can reproduce the essential Spawn experience: open a link, enter a responsive multiplayer world, walk freely, interact with persistent objects, and change that world while people remain inside it. The engine must support multiple games through stable content and scripting contracts. Darkwind is its first substantial game (the reference game) and is a new design, without a compatibility requirement for the existing MUD.
The deliverable is an engine, authoring environment, multiplayer runtime, asset pipeline, and deployment system. A three-room demonstration is an acceptance fixture within that program. It is not the complete engine or the final scope.
This document defines the proposed architecture. The roadmap makes it executable through milestones, dependencies, and tests. The research record separates verified public capabilities, indexed technical clues, and independent design choices. Everything below is our proposed design unless explicitly attributed to a source.
#Reading guide
- Requirements and scope
- Architecture decisions
- Processes and workers
- ECS and state model
- Simulation and physics
- Custom renderer
- Places and portals
- Authority and network recovery
- Persistence
- World format and scripting
- Editor and collaboration
- Assets, audio and input, and game systems
- Advanced worlds and AI tools
- Deployment, budgets, and validation
- Package ownership, effort, and completion
#Product requirements
#Player experience
Players enter through a URL, select or restore a character, and receive usable controls before the entire world has downloaded. Walking and camera movement respond locally. Other players move smoothly. Doors, objects, NPCs, effects, and environmental changes are shared. Reconnection restores an internally consistent world and character.
The initial spatial model is a graph of places. Each place is a freely walkable 3D space with entrances and exits. A place can represent an interior, outdoor clearing, street, dungeon chamber, or large streamed region. Place boundaries do not imply a new WebSocket or server process.
Keyboard and mouse are the first supported control scheme. Touch and gamepad consume the same action definitions. Text chat, accessible UI, reduced-motion options, configurable controls, and clear connection state belong to the engine shell.
#Builder experience
Builders can create a world from a template, place objects, edit properties, attach behaviors, import assets, invite collaborators, inspect running state, and publish an immutable release. Editing a door should update that door while unrelated entities continue running. A faulty script should produce a useful diagnostic and preserve the last valid world.
An external coding agent or an in-product assistant uses the same content schema, commands, tests, and permissions as human tools. It can prepare changes, preview them, inspect evidence, and apply bounded transactions. AI generation is optional and never required to render, simulate, or join an already authored world.
#Engine success criteria
The engine is ready to build upon when a second game can be created using public APIs and content files without modifying engine internals; an upgrade has explicit migration and rollback procedures; the same world runs locally and on a deployed server; and published performance, correctness, and compatibility fixtures pass.
An unlimited world or unlimited player count is not an engineering requirement. The product may grow by streaming and partitioning, but each published release declares tested capacity per room, process, region, device tier, and content profile.
#Scope and capability levels
Use three release levels to prevent the prototype from silently becoming the product definition.
| Capability | Engine preview | Engine version 1 | Extended Spawn-like capability |
|---|---|---|---|
| 3D presentation | Custom WebGPU, basic PBR, shadows, GLB, animation | Adaptive quality, bounded lights, material graph, profiling, picking | Advanced atmosphere, vegetation, water, improved GPU culling |
| Core simulation | ECS, fixed step, input, events, deterministic fixtures | Stable component/plugin API, migrations, headless runtime | Larger simulations and specialist systems |
| Multiplayer | Browser-owned relay, snapshots, deltas, fenced handoff | Trusted-host profile, interest filtering, bounded recovery, regional rooms | Cross-process travel, large-world partitioning |
| Physics | Shared character controller and pinned physics adapter | Rigid bodies, joints, triggers, moving platforms, full recovery tests | Owned replacement backend, vehicles, ragdolls, buoyancy |
| Places | Linked authored places, preloading, server-accepted crossings | Visible one-level portals and bounded streaming | Recursive portals and physical objects crossing portals |
| Persistence | World release, snapshot, journal, reconnect | Player state transactions, backups, migrations, content/state separation | Persistent terrain and long-running world jobs |
| Authoring | World files, schemas, CLI, inspector, transform editing | Multiplayer editor, undo, prefab overrides, scripts, playtest, release management | Terrain/voxel brushes, visual behavior tools, rich material tools |
| AI tooling | Read-only observation and proposed structured patches | Permissioned edits, test loop, preview, provenance, asset jobs | Agent playtesting and specialized content workflows |
| Game modules | Interactions, inventory example, NPC example | Reusable actors, abilities, dialogue, quests, equipment extension points | Specialist vehicle, crafting, strategy, and simulation modules |
| Other presentation modes | Camera abstraction and sprite schema reserved | Billboards and orthographic cameras | Full tilemaps and 2D physics profile |
| Platform | Supported desktop WebGPU configurations | Tested touch/gamepad and device tiers, session/account management | Additional GPU backends and broader browser coverage |
Extended capabilities remain part of the program. They have separate milestones and must not delay proving the common runtime contracts.
#Decisions that establish the architecture
- Own the engine core and renderer. Implement the ECS, scheduler, world compiler, replication protocol, authoring commands, and WebGPU renderer. Babylon.js and Colyseus remain comparison/reference options, not the core product architecture.
- Use TypeScript across orchestration, tools, and runtime. Use WGSL for GPU shaders. Use WebAssembly where a mature dependency or measured numerical/CPU need justifies it. A blanket rewrite in Rust or C++ is not a prerequisite.
- Separate deterministic simulation from presentation. A rendered pose, camera shake, particle count, audio source, and GUI transition never become gameplay truth merely because they are visible.
- Implement browser-owned relay and trusted-host profiles on one schema. The relay profile is the first target for Spawn-like cooperation and immediate ownership. The trusted-host profile supports persistent competitive rules. A world chooses its authority policy explicitly.
- Use a mature physics backend first behind an owned interface. Start with a pinned Rapier WASM build. An owned physics replacement is an extended milestone with equivalence and performance gates. There is no claim that this recreates Mantle's implementation.
- Use a custom versioned WebSocket protocol first. Add alternative transports only when measured latency, ordering, or bandwidth problems justify them.
- Keep content revisions separate from gameplay state. Editing a chest model does not replace the chest's live inventory. Reverting source does not implicitly revert economic transactions.
- Use explicit transactions and one writer per authority domain. Collaboration, ownership changes, publication, and persistent rewards require their own atomic boundaries.
- Optimize through budgets and evidence. Every collection, queue, script, shader, stream, and cache has a bound, owner, and observable failure behavior.
- Start with authored connected places. General terrain and voxel systems build on the same streaming and persistence contracts later.
#System architecture
View diagram source
flowchart TB
subgraph Browser
UI[Main thread UI input editor]
SIM[Simulation worker ECS physics scripts]
RENDER[Render worker WebGPU presentation]
UI -->|actions and edit intents| SIM
SIM -->|render deltas and transforms| RENDER
SIM -->|observations| UI
UI -->|camera and viewport intent| RENDER
end
SIM <-->|versioned protocol| RELAY[Room coordinator and relay]
RELAY <-->|authority domains| HOST[Optional trusted simulation host]
RELAY --> JOURNAL[Durable room journal and snapshots]
HOST --> PLAYER[Transactional player state]
UI <-->|authoring transactions| CONTROL[World control and publication service]
CONTROL --> CONTENT[Immutable world releases]
CONTROL --> BUILD[Asset and script build workers]
BUILD --> CDN[Content addressed assets]
CDN --> RENDER
CONTENT --> SIM
CONTROL --> ASSIST[Permissioned agent and assistant tools]These are logical boundaries. Initially, the coordinator, API, publication service, and storage access can be modules in one Node.js deployment. The simulation host runs in a separate worker/process when enabled. Asset processing runs in job workers. Decompose services only when isolation, scaling, or deployment requires it.
#Browser execution
The main thread owns DOM UI, keyboard/mouse/touch collection, accessibility, pointer lock, browser permissions, and editor widgets. It sends semantic input actions rather than DOM events into gameplay. Typing into chat must stop gameplay key handling; losing focus must release held actions.
The simulation worker owns canonical local simulation state, authority checks, the fixed-step loop, physics, behavior execution, and network ingress/egress. A renderer failure cannot mutate the game state. A stalled UI cannot hold a movement key forever; input sampling carries sequence and freshness information.
The render worker owns GPU resources and presentation state through OffscreenCanvas where the capability probe passes. A main-thread render placement remains available for supported configurations that lack the required worker path. This is a thread-placement fallback, not a second graphics backend. OffscreenCanvas reference
Start with transferable buffers, explicit ownership, and bounded message queues. Transforms may replace older unsent transforms; entity creation, destruction, resource references, and revision barriers may not be dropped. Add SharedArrayBuffer only after profiling, with the required cross-origin isolation headers and a transfer-buffer fallback. Shared memory reference
The render protocol carries a generation and baseline revision. A gap in structural updates requests a presentation snapshot. Buffer pools cap allocation; returned buffers are checked against generation before reuse. A blocked consumer cannot create unbounded producer memory.
#Headless execution
The same simulation package must run without DOM, canvas, GPU, browser globals, or audio. It supports trusted hosting, replay validation, bots, snapshot inspection, and deterministic tests. Visual asset bounds and colliders are build artifacts, so gameplay never needs a render process to answer a collision or dimensions query.
#Core data model
#Identity and transforms
Use stable persisted IDs for authored entities and globally unique IDs for spawned persistent entities. Runtime ECS handles are compact index-plus-generation values. Network handles are connection-scoped dictionary entries, never durable identity. Mapping between these layers is explicit and invalidated on generation changes.
A transform has place identity, parent identity, position, quaternion rotation, and scale. Define meters, seconds, radians, a right-handed coordinate system, Y-up, and -Z-forward in the format specification. Reject transform cycles. Rendering may support nonuniform scale; physics shapes declare supported scaling and bake unsupported cases during import.
Place-local coordinates avoid forcing the entire world into one floating-point coordinate range. Large places use cells or a local origin. Portal transforms connect two local coordinate frames; they do not require neighboring places to share physical coordinates.
#ECS storage and mutations
Implement sparse-set component storage with typed arrays for frequent numeric fields and bounded structured records for infrequent data. Entity queries iterate relevant component sets. Systems declare read/write sets and scheduling dependencies. Defer structural changes until defined barriers so an iteration cannot invalidate itself.
All canonical mutations pass through a registry-backed write API. Each component declares schema version, serialization, persistence class, replication visibility, authority domain, change comparison, migration, and whether prediction includes it. The same metadata drives validation, inspector forms, documentation, and codecs.
Keep separate dirty cursors for rendering, networking, persistence, and diagnostics. A slow reader cannot force indefinite history retention; it receives a new baseline after a documented retention limit. Each write batch names its tick and transaction. Entity destruction creates a tombstone before compacting local state.
Initial components include Transform, PlaceMembership, Parent, RenderMesh, MaterialRef, Collider, RigidBody, CharacterMotor, AnimationState, InputOwner, AuthorityDomain, Interaction, BehaviorState, PersistentIdentity, AudioEmitter, Light, and Tags. Game packages register their own typed components without adding Darkwind-specific fields to core.
#State lifetimes
| Class | Examples | Storage and recovery |
|---|---|---|
| Authored definition | Door prefab, material, spawn template, script reference | Immutable content release plus source history |
| Persistent gameplay | Inventory, completed quest, opened persistent door | Transactional state or durable world events |
| Recoverable session | Physics pose, currently seated player, active encounter | Snapshot plus bounded replay/catchup policy |
| Ephemeral event | Footstep, impact flash, chat typing indicator | Expiring event stream; no replay as new activity |
| Local presentation | Camera smoothing, interpolation cache, particle buffers | Rebuilt locally; never authoritative |
Every mutable property has one defined class. A component can split fields into different components when their lifetimes differ. Do not persist the entire ECS indiscriminately.
#Simulation and time
The default simulation rate is 30 Hz, pinned by the world release. A fixed accumulator handles elapsed time with a maximum catch-up count. When a client falls too far behind, it requests recovery or yields authority; it does not execute an unlimited backlog or silently accelerate the world.
The step order is: validate and stage ingress; apply accepted transactions and ownership changes; consume input; run behavior intent systems; resolve character and physics movement; resolve interactions; finalize state/events; publish change batches; schedule persistence outside the tick. Systems with dependencies use explicit ordering, not import order.
Simulation time is tick-based. Room lifecycle time comes from a coordinator clock. Lease expiry uses coordinator monotonic time. Presentation time uses local elapsed time. Wall-clock timestamps are for audit and offline progression policies. Never compare values from these clocks without an explicit conversion.
Deterministic replay records the initial snapshot, engine/physics/script hashes, ordered inputs, random seeds, and external event results. Use a seeded PRNG; stable entity ordering; controlled floating-point conversions; serialized async results at tick boundaries; and deterministic math where required. Math.fround() alone does not establish determinism. Cross-browser and headless replay must prove the supported contract.
Pause and offline semantics are explicit. With no players, a relay world pauses unless a trusted host is assigned. Timed crops or cooldowns may use elapsed-time formulas on wake; simulated physics does not pretend to have advanced through an absent host. Replays never perform purchases, writes, or external requests a second time.
#Physics and movement
The owned physics interface exposes shapes, rigid bodies, triggers, raycasts, sweeps, contacts, joints, character motion, snapshot/restore, and determinism metadata. The initial backend uses a pinned Rapier WASM version; identical initial conditions, object creation order, and surrounding computation remain necessary. Rapier determinism
The engine owns character behavior: acceleration, deceleration, air control, gravity, step height, slope limit, crouch clearance, jump buffering, ground snapping, and moving-platform support. These are world-configurable within server-approved bounds. Collision geometry is distinct from visible geometry; avoid triangle-mesh collision for every decorative item.
Doors and moving platforms have authored interaction and collision states. A visually loading floor remains blocked or uses a valid proxy until its real collision is ready. Streaming out geometry under a character is forbidden. Moving platforms carry riders through relative transforms, with matching simulation and presentation rules.
Connected dynamic bodies and joints form an authority island. One simulator resolves that island. Two browser owners must not independently solve opposing impulses and both publish results. Initially, player-owned kinematic characters collide with static geometry; interaction with shared dynamic bodies is submitted to the place/island authority. Competitive avatar collision and contact-dependent combat use trusted-host authority. Ownership transfer freezes or buffers affected interactions until the island's new epoch is active.
The owned replacement physics backend is a separate workstream: broad phase; shape primitives and convex collision; narrow phase; contact manifolds; sequential impulse solver; friction/restitution; sleeping; continuous collision; joints; character sweeps; snapshots; deterministic ordering; and profiling. It replaces the adapter only when the shared fixture suite passes. Vehicles, ragdolls, and buoyancy follow those fundamentals.
#Rendering architecture
#Backend and capabilities
Implement a custom WebGPU renderer in TypeScript/WGSL. The first supported tier requires a successful capability probe on declared desktop browser/OS/GPU configurations. API presence alone is insufficient: request a device, validate limits/formats, initialize essential pipelines, and draw a probe scene. WebGPU availability is platform-dependent. WebGPU reference
An unsupported device receives a clear compatibility result before joining as an active simulation owner. A custom WebGL2 backend is an extended compatibility milestone, with a capability matrix; do not promise shader parity or implement two backends before the first is stable.
#Render data and resource lifetime
The renderer receives a presentation scene derived from ECS changes. It owns meshes, materials, skeletons, texture residency, draw batches, lights, and cameras. A render handle is not an ECS entity reference. All resources carry generation, content hash, reference ownership, and disposal state.
Resource references remain alive while any current draw record needs them, even if an upstream source component is evicted. Deferred disposal waits for safe GPU completion. Pipeline and texture caches have memory budgets and eviction policies. Device loss recreates the device, pipelines, and resources from a bounded CPU-side description; repeated failures degrade or exit cleanly instead of restarting indefinitely.
#Rendering stages
Start with a forward renderer: depth, opaque PBR, alpha-tested materials, transparent objects, particles/billboards, postprocessing, and UI composition. Add clustered/Forward+ lighting only after the baseline passes image and timing tests. A render graph declares resources and dependencies, making portal views, shadows, and postprocessing explicit consumers.
Core material features are metallic/roughness PBR, normal/emissive/occlusion maps, unlit materials, alpha cutoff, sidedness, and correct color-space handling. Lighting includes ambient/environment light, a directional sun, bounded point/spot lights, and a shadow budget. Prefer baked lighting/probes for static interiors. Specify linear intermediate color and output tone mapping; validate texture orientation, tangent space, and scale conventions.
Visibility begins with CPU frustum culling, place membership, LOD, and instance batching. Add GPU culling/indirect draws when measurements justify it. Geometry, material, and pass sorting reduce state changes. Dense repeated scenery uses instancing. Skinning, morph targets, and animation blend graphs are bounded by visible actor and bone budgets.
Presentation interpolation runs independently of simulation. Equipment attached to bones follows the displayed skeleton in the renderer. Camera sway, hit shake, recoil, and squash effects modify presentation transforms only. Remote entities have a bounded interpolation buffer, limited extrapolation, and a stalled-state animation instead of endless running.
#Materials and effects authoring
Version 1 provides a typed material/effect graph compiled into controlled WGSL templates, with validated inputs and precompiled variants. Engine developers may write raw WGSL; public creators do not receive unrestricted device access. Shader resource bounds, compilation errors, and GPU timing appear in the inspector. A new material activates only after compilation succeeds; failure keeps the previous valid material.
Particles start with pooled CPU emitters for low counts, then a compute path for large effects. Emitters declare lifetime, spawn cap, bounds, collision mode, and quality scaling. Cosmetic particle physics is separate from gameplay projectiles. Sprite animation and world text are supported before general 2D tilemaps.
#Places and streaming
A world contains place definitions, spawn anchors, portal edges, and optional spatial cells. The current place, visible destination windows, nearby cells, and predicted travel direction determine an interest set. That set drives separate requests for asset residency, simulation activation, and network subscription; these are related but not identical.
Each content unit moves through absent, fetching, decoded, collision-ready, GPU-ready, active, and cooling states. Cancellation carries generation and content hash. A late fetch from a previous place or release cannot install stale content. Preload adjacent destinations under bandwidth and memory budgets; do not preload the entire room graph.
Stable loading priorities are collision needed for immediate safety, essential player/interaction assets, nearby environment, visible destination, and decoration. Reuse prefabs and materials across places. When a budget is reached, reduce distant quality before evicting essential collision or gameplay state.
#Portal travel
A portal names its source plane, destination place/anchor, traversal transform, conditions, and presentation mode. The authority validates a crossing intent. It commits place membership, position, velocity/orientation transformation, and transferred attachments in one transaction. Each crossing has an idempotency key and old/new authority epochs; retries cannot duplicate a character or inventory.
For same-host places, a crossing preserves the session. The client can pre-render and predict presentation, but destination gameplay becomes active at the accepted transition. Closed or denied exits never leave half the party in an uncommitted place. Colliders and the minimum destination asset set must be ready before releasing the character.
Visible portals first use one extra bounded camera pass with destination clipping and an offscreen render target. Limit pixel coverage, portal count, recursion depth, and refresh rate by device tier. Later depth/stencil composition and recursive views have separate tests for clipping, occlusion, physics, and budget growth.
Cross-host travel uses prepare, source freeze, destination restore, durable commit, and source retirement under a coordinator transaction. A timeout has one recoverable owner. Items do not exist in two rooms while a retry runs. Cross-world travel additionally applies explicit capability, asset, inventory, and identity policies; arbitrary worlds cannot import privileged scripts or rewards.
#Multiplayer authority
#One schema with two profiles
The relay-owned profile gives an approved browser authority over its avatar and allows an eligible browser to host shared place/island domains. The server authenticates writers, grants epochs, orders durable changes, enforces protocol limits, and relays state. It does not solve gameplay physics. This profile supports cooperative construction and low-cost social worlds. A valid browser owner can still falsify its simulated results; leases do not make an untrusted simulation honest.
The trusted-host profile assigns gameplay domains to the engine's headless runtime. Browsers submit inputs and predict their own movement. The host simulates, validates interactions, and commits durable outcomes. Rendering remains local. This profile is the default for Darkwind releases with progression or competitive rules; relay-owned mode remains available for builder sessions and cooperative worlds.
Worlds pin the profile in their release. Do not switch an active room's authority semantics by changing a UI flag. A supported migration requires a snapshot, new room generation, epoch transfer, and compatible replay policy. Components can be cosmetic/local without participating in either gameplay authority mode.
#Authority domains and fencing
Every replicated gameplay component names an authority domain: avatar, place, physics island, or trusted service. The coordinator stores the current owner, monotonic epoch, room generation, and lease expiry. It grants transitions atomically in the room's ordered log. Writer identity comes from the authenticated connection, not a user-provided packet field.
An update includes domain and epoch. The coordinator rejects a stale writer before accepting durable state or forwarding it as current authority. Receivers also reject stale generations. Authority is checked at the smallest useful domain boundary; giving a player an avatar never grants control of another character, a shared chest, or a player ledger.
Browser host candidates must be ready, caught up, compatible with the pinned engine, visible/active enough to meet the tick budget, and within resource limits. The coordinator uses a deterministic rank among eligible candidates and applies hysteresis to avoid churn. A hidden or unhealthy host voluntarily yields where possible. Forced lease expiry is governed by coordinator time, not competing client clocks.
#Host handoff
- Mark the old domain as draining; stop accepting new interactions that cannot finish before the barrier.
- Capture a state snapshot at tick T with script/physics state and the accepted input cursor.
- Persist or durably reference that snapshot and its subsequent accepted changes.
- Grant epoch E+1 to a caught-up successor; the old epoch is fenced.
- The successor restores, validates content and schema hashes, catches up, then announces ready.
- Release buffered interactions against the new epoch; reject/retry those whose preconditions changed.
If the old owner disappears, restore the latest recoverable checkpoint. Session motion may rewind within the declared recovery window; acknowledged durable transactions may not. If no candidate exists, pause that simulation domain or start a trusted host according to world policy. The UI displays the actual condition.
Cross-domain interaction is an intent submitted to the receiving authority. A pickup, mount, joint attachment, or ownership transfer names expected revisions and an idempotency key. The coordinator commits the ownership/state transition once. Arbitrary last-writer-wins merging is not acceptable for inventory or exclusive possession.
#Wire protocol and recovery
#Transport and envelopes
Use TLS WebSockets initially. Build bounded queues, monitor buffered bytes, coalesce unsent motion, and prioritize essential control messages. WebSocket does not provide application-level receive backpressure; an overflowing ingress queue triggers bounded resynchronization or disconnect. WebSocket reference
The initial diagnostic encoding is schema-validated JSON. Before the performance milestone, generate a binary codec from the same schemas: stable numeric message IDs, component dictionaries, quantized optional motion fields, lengths, and protocol version. Compare raw binary, compression, CPU cost, and small-message latency before choosing compression defaults. Never put a whole room snapshot behind a giant synchronous parse.
Every message is bounded by byte length, collection counts, nesting, identifiers, and finite numeric checks. Envelope fields include protocol version, room generation, connection generation, lane, message kind, sequence or input number, authority epoch where applicable, and schema/content hash at negotiation boundaries.
#Traffic lanes
| Lane | Semantics | Examples |
|---|---|---|
| Control | Reliable, ordered, idempotent | Join, lease grant, barrier, release selection, subscription change |
| Durable change | Reliable, ordered, journaled before durable ACK | Spawn persistent entity, delete, accepted edit, ownership transfer |
| Motion | Latest sample wins within generation and tick | Position, velocity, facing, locomotion |
| Gameplay intent | Ordered by processing authority, deduplicated | Interact, attack, use item, cross portal |
| Ephemeral event | Event ID and expiry, bounded replay rules | Sound, impact, temporary particle effect |
| Asset reference | Hash-addressed, fetched over HTTP | Model, collision bundle, script module |
These are logical lanes on the first socket. Reliable TCP still has head-of-line blocking, so a late motion sample cannot bypass bytes already written. Bound outgoing buffers and keep assets off the socket. Evaluate a separate motion transport or WebTransport only after a measured need and an equivalent fallback design.
#Join and resume
The join state machine is disconnected → authenticating → negotiating → loading baseline → catching up → live, with explicit suspended, resyncing, and failed states. A connected socket is not a live session.
The welcome pins room generation, engine/content release, protocol schema hash, authority assignments, snapshot reference, and a durable barrier sequence S. A snapshot is immutable and complete through S. The server buffers or retains durable deltas after S while the client loads it. The client applies snapshot then deltas exactly in sequence, installs a fresh motion baseline after catchup, and acknowledges readiness before it can host anything.
Resume tokens bind account/session, room, expiry, generation, and last durable acknowledgment. If retained history is sufficient, replay the missing suffix. Otherwise send a fresh snapshot. Token verification and generation fencing prevent a stale tab from silently reviving an old session. Sequence cursors advance only after successful application, not after receipt or decompression.
Use separate sequence spaces for independently subscribed scopes, or include explicit skip/range markers when filtering a global journal. A client must not mistake events withheld by interest filtering for packet loss. Interest entry sends a full entity baseline and scope revision; exit removes local presentation without deleting the durable entity.
#Reliable state interpretation
CREATE includes complete required identity and component schema. UPDATE never silently creates an unknown entity. Unknown references request a baseline or wait in a small bounded dependency queue. DELETE carries a tombstone and revision. Snapshot compaction retains enough deletion information to prevent an old reconnect from resurrecting an entity.
Bundle transaction rows atomically. Independent malformed rows may be rejected independently only when the envelope explicitly declares them independent. Dropping half a pickup or half a portal transition would violate game state. Report malformed sender data without allowing one packet to kill every honest participant.
Periodic head announcements include the current durable revision and content revision. They detect a missed edit even when no later gameplay message touches that object. ACK processing has its own cursor and deduplication: an author's acknowledgment can arrive after higher-sequence peer updates without losing the author's own accepted event.
#Prediction and interpolation
Relay-owned avatars publish their canonical movement. Shared authoritative results still arrive asynchronously. Trusted-host avatars retain numbered input commands, predict them through the shared movement module, compare host snapshots, restore authoritative state, and replay unacknowledged inputs. Correction affects simulation immediately and presentation through a bounded smoothing policy; large errors snap with diagnostics.
Remote motion uses timestamped samples and adaptive interpolation within configured bounds. Extrapolation has a strict duration cap. Animation state and impact cues align with the displayed pose. Cosmetic smoothing never delays or duplicates an authoritative reward or damage transaction.
#Interest and scaling
Begin with place-based interest plus nearby portal destinations. Large places add a spatial grid. Filter replication on the server before encoding per-recipient data. Hidden entities and private player fields are not sent merely to be hidden by the renderer.
Broadcast fanout can grow quadratically with a dense crowd. Establish explicit room limits and density tests. Shard across room instances or regions when that is acceptable to game design. No protocol optimization makes an arbitrary crowd free; the engine must expose capacity and admission policy.
#Persistence and consistency
#Storage responsibilities
Use PostgreSQL initially for accounts, memberships, release metadata, accepted durable events, player state, and transaction records. Use object storage for immutable assets, release bundles, and large snapshots. A room coordinator maintains hot state in memory, backed by durable commits. Single-process ownership is acceptable initially; multi-process ownership requires a fenced room lease stored in the database.
The source workspace is versioned separately. A release manifest pins engine version, format version, behavior hashes, asset hashes, physics backend, and authority profile. Each running room names exactly one active content revision, except during a defined transition barrier.
#Durable acknowledgment
An acknowledged durable transaction must survive a process crash. Commit its event, resulting durable state or checkpoint reference, idempotency record, and publication outbox in one database transaction where required. Fanout may happen after commit and be retried. An ACK for mere receipt has a different type and cannot be displayed as saved.
Hot motion is not written to PostgreSQL every tick. Store recoverable pose snapshots at a budgeted cadence. Default prototype recovery objectives are zero loss of acknowledged durable transactions and up to five seconds of recoverable motion after abrupt host loss. Those are acceptance targets to test, not achieved guarantees.
#Checkpoints and compaction
A checkpoint captures a consistent ECS revision, persistent behavior state, physics state/version, authority metadata, and content manifest. Write the immutable snapshot, verify its hash, then atomically advance the journal's checkpoint pointer. A crash before pointer advancement leaves an unused snapshot; a crash after advancement leaves a valid referenced snapshot.
Replay is pure state application or deterministic simulation, with side effects suppressed. Compact only journal ranges covered by a verified checkpoint and retention policy. Keep backup manifests and a tested restore path. Database backups alone do not preserve external object-store assets unless their retention is coordinated.
#Gameplay transactions
Inventory changes, trade, quest rewards, resource claims, and purchases have stable transaction IDs, expected revisions, authorization, and atomic debit/credit semantics. A durable entity has one authoritative location: world, inventory, container, or retired. Cross-host transfer retains one owner through prepare/commit recovery.
A relay-owned room can persist user-authored world state, but it cannot convert an untrusted client claim into a trusted economy reward. Trusted reward rules run on the trusted host or trusted service against sufficient validated state. This is a product-level distinction exposed in the world configuration.
#Content and state migration
Each release declares migrations for component, script-state, asset, and persistent data changes. Preview migrations against a copied snapshot. Published upgrades drain or stage rooms, migrate into a new generation, verify, then admit players. Keep the previous release available.
Code rollback is safe only while stored data remains backward-compatible or an explicit reverse migration exists. Economy history is not undone by source rollback. Deleting an authored entity with live persistent contents requires a policy: retain as orphaned, move contents to recovery storage, or migrate to a replacement. It never silently discards them.
#World format and compilation
Use human-editable YAML or JSON for source, compiled into a canonical validated intermediate representation. YAML aliases, implicit coercions, duplicate keys, and recursive expansion require restrictive parsing. JSON is the canonical interchange and wire representation. Runtime workers never parse a complete authoring repository on each frame.
Example proposed manifest:
format: 1
id: darkwind-preview
engine: 0.1.0
entryPlace: tavern
simulation:
tickRateHz: 30
authority: relay-owned
physics: rapier-pinned
content:
places: places/*.place.yaml
prefabs: prefabs/*.prefab.yaml
behaviors: behaviors/*.ts
limits:
playersPerRoom: 16
activeBodies: 128Example place fragment:
id: tavern
spawn: { position: [0, 0, 2], facing: 0 }
entities:
- id: tavern.front-door
prefab: hinged-door
transform: { position: [0, 0, -6] }
components:
interaction: { actions: [open, close] }
portal: { destination: courtyard, anchor: tavern-entrance }
persistence: { state: world }These examples describe intended schemas; they are not implemented APIs. A release compiler resolves prefabs and overrides, detects cycles and missing references, validates scripts/colliders, produces dependency graphs and content hashes, and emits source-mapped diagnostics. Stable authored IDs survive reorder and renaming of display labels.
Prefab instances track the prefab revision and explicit property overrides. Changing a prefab preserves instance overrides; removed fields and conflicting migrations require diagnostics. Builder source remains human-editable after tool or AI changes.
Compiled artifacts include world/place manifests, component schema dictionary, optimized visual assets, collision shapes, navigation data, script bundles, source maps, and a dependency index. Cache keys include tool versions and settings. Builds are reproducible within declared tooling constraints and do not trust filenames as version identity.
#Behavior runtime and plugin API
#Public behavior contract
Behaviors expose lifecycle hooks such as onSpawn, onInput, onInteract, onTick, onEvent, onSuspend, and onDespawn. Persistent fields are declared in a schema with defaults and migration. A behavior receives an entity-scoped capability context, immutable observations, seeded randomness, and a command buffer.
export const doorBehavior = defineBehavior({
state: { open: booleanField(false) },
onInteract(ctx, event) {
if (event.action !== "open") return;
ctx.commands.setState({ open: true });
ctx.commands.emit("door.opened", { actor: event.actor });
}
});The engine validates authority and preconditions before applying commands. Scripts cannot bypass ownership by writing to raw ECS arrays. Rendering, networking, storage, and OS APIs are unavailable inside deterministic hooks. Async jobs return typed results at a later tick with request IDs; they never resume a stale entity context implicitly.
#Trusted author phase and creator isolation
The preview executes developer-controlled modules inside a dedicated simulation worker with a watchdog and restartable checkpoints. This protects responsiveness but is not a security sandbox for arbitrary third-party code. A worker still has capabilities and can hang or exhaust memory.
The watchdog runs outside the worker it supervises. If a trusted script blocks the worker, terminate that worker and restore its last committed checkpoint; a timer inside the blocked worker cannot interrupt it. This coarse recovery is acceptable for the trusted-author preview. The restricted runtime must provide finer execution budgets before public creators are admitted.
Before admitting untrusted creators, execute behavior code in an embedded VM/WASM runtime with bounded instructions, memory, module imports, and exposed host functions, or use a restricted interpreted behavior language. Select the implementation through a dedicated isolation spike. Do not use eval, new Function, or node:vm as a claimed hostile-code boundary.
A script transaction stages commands and commits only after successful completion. Exceptions or budget exhaustion discard its uncommitted commands. Repeated faults park the behavior until its own code or configuration changes. Updating an unrelated light must not restart a permanently failing script.
#Scheduling and plugins
Separate deterministic systems, low-rate AI tasks, async jobs, and presentation callbacks. Scripts declare their needed cadence; a quiet NPC does not require a full behavior execution every frame. Global and per-world budgets cap spawned entities, outstanding jobs, event fanout, and script work.
Plugins register namespaced schemas, systems, commands, editor panels, and migrations. Engine internals remain private. Plugin compatibility is checked against the engine API version. Native/server plugins are operator-installed; creator plugins use the restricted runtime. Game content cannot import server credentials or unrestricted network capabilities.
#Editor and live collaboration
#Authoring surfaces
The editor provides a scene tree, viewport selection, transform gizmos, property inspector, prefab browser, asset browser, behavior editor, console, performance view, history, and playtest controls. It operates on source definitions through the same command API used by the CLI and assistant.
Every edit transaction carries actor, base revision, operation ID, affected entities/properties, and preconditions. The authoring service serializes commits per world. Disjoint property edits can rebase; conflicting changes return a specific conflict. Transform dragging uses ephemeral presence/preview messages and commits a final or throttled durable command. It does not write hundreds of Git commits per second.
Use soft selection locks for feedback, but enforce correctness through revision checks. Text editing may later use a proven CRDT; object graph, scripts, and gameplay transactions do not automatically become conflict-free by adopting a CRDT library.
#Live application
Validate a candidate revision; compile changed dependencies; prepare resources in active sessions; assign an activation barrier; then atomically apply the compatible changes. Unchanged entity runtime state survives. Script replacement calls an explicit state migration. Physics topology changes activate at a tick boundary. A failed asset or shader retains the previous valid resource.
Each room reports accepted, applying, applied, or rejected for the new content revision. Periodic revision announcements repair a missed push. The editor's saved state, compiled state, and running-room state are displayed separately so a successful file save cannot be mistaken for a successful live update.
The activation barrier is atomic within a room's simulation, not a promise that every remote GPU updates at the same wall-clock instant. A slow client may display the previous revision briefly, but cannot remain an authority writer with incompatible content. Fence its writes, catch it up, and grant readiness again. Put a timeout on preparation so one disconnected editor cannot hold all players indefinitely.
Undo creates a compensating transaction with preconditions. If someone edited the same field afterward, undo must merge intentionally or report a conflict. Undoing an object deletion can restore authored content, but it does not reverse later player trades or arbitrary gameplay effects.
#Publication and Git
The local CLI reads an ordinary Git workspace and produces a release bundle. Server-side repository integration initially imports explicit commits or signed upload bundles; a dedicated Git hosting service is optional later. Browser edits create source transactions that can be materialized as commits.
Development sessions follow a mutable branch revision. Published sessions pin an immutable release. Publish validates, builds, records the release, and updates the public routing pointer atomically. Existing sessions either stay pinned or migrate through an announced policy. Preview links specify world, release, place, and access scope without embedding long-lived credentials.
#Asset pipeline
Use glTF/GLB as the initial model/animation interchange, with a documented supported subset and extension policy. Importers normalize units, transforms, materials, texture orientation, skeletons, and animation names. Unsupported features produce warnings or errors before publication. glTF reference
Build jobs validate and optimize meshes, generate LODs where useful, compress textures, bake collision proxies, extract bounds, and generate thumbnails. Keep original assets and provenance separately from runtime variants. A derivative hash includes source bytes, importer version, and processing settings.
Asset state progresses through uploaded, validated, processing, ready, or failed. Placeholders carry meaningful dimensions and safe collision behavior. A generation job retries with an idempotency key and cannot overwrite a newer accepted asset. Decoding and GPU installation are budgeted across frames.
The runtime uses a manifest mapping logical names to immutable hashes and variants. HTTP caching uses immutable content URLs; only manifests need revision checks. A reference-counted memory manager covers decoded CPU data, GPU data, audio buffers, and cached portal views. Instrument allocations and eviction, not just network bytes.
Future asset-generation providers plug into a job interface for images, models, sound, animation, and variants. The provider returns artifacts plus metadata, never directly mutates the live ECS. Human or automated validation checks scale, topology, bounds, materials, and generation quality before promotion.
#Audio input and interface
WebAudio owns buses for master, music, ambience, dialogue, and effects. Spatial emitters follow rendered poses; attenuation and optional occlusion are bounded. Browser gesture requirements are handled through one audio activation flow. Shared music uses a room clock and local correction, rather than transmitting audio frames from the simulation host.
Semantic action maps define move, look, jump, interact, inventory, and game-specific actions. Keyboard/mouse, touch, and gamepad bind to those definitions. Pointer lock and full screen are requested through explicit player actions. Text entry, menus, focus loss, and reconnection release movement consistently.
HUDs use an engine-owned DOM layer and a restricted data/event bridge. Trusted developer UI may be bundled directly; creator HTML runs in a separate-origin sandbox with a validated message protocol and controlled navigation. UI code cannot acquire gameplay authority through postMessage. Keep text legible, provide semantic controls, expose remapping, and respect reduced motion and audio preferences.
#Reusable gameplay systems
Game-facing packages provide interaction discovery and prompts; actor templates; inventory/container primitives; equipment attachment; health/resources; ability scheduling; dialogue state; quest/objective signals; NPC perception and navigation; and configurable spawn/despawn policy. The engine defines mechanism and lifecycle; games define lore, progression rules, content, and balance.
Navigation starts with authored walkable surfaces and baked navigation meshes. NPC planning runs at a bounded lower cadence while locomotion runs each tick. Path requests carry place and navmesh revisions; stale paths are discarded. Dynamic doors update connectivity through explicit blockers. Avoid globally recalculating paths on every movement update.
The first game module demonstrates combat without making a specific combat model mandatory. Damage is an authoritative command and animation is its presentation. Cooldowns, cancellation, death, loot, and respawn have explicit state transitions. Game modules emit typed events suitable for UI and persistence.
Darkwind owns its own game repository/package. A second fixture game, such as a cooperative physics puzzle, must reuse the engine without importing Darkwind. That test is the strongest check against accidentally building a one-off game framework.
#Terrain voxels and advanced worlds
Terrain is a separate feature package using the place streaming interface. A heightfield implementation comes first, with chunked visual mesh, collision, material layers, LOD seams, and persistent edit operations. Voxel terrain follows with chunk coordinates, versioned density/block data, meshing jobs, boundary consistency, and bounded edit history.
Terrain edits commit data changes before publishing regenerated geometry. Visual and collision generations must remain compatible; hold movement or retain old safe collision while a replacement is being built. Undo names an edit operation and checks intervening modifications. A global rebuild on every dig is prohibited by the chunk contract.
Vegetation, water, weather, day/night lighting, and sky are presentation systems driven by a small shared environment state. Dense foliage uses instancing and distance budgets. Swimming and buoyancy are gameplay/physics modules. Rivers and terrain generation use seeded, versioned recipes with cached output. A seed alone is insufficient when the generator version changes.
Vehicles introduce seat ownership, input routing, suspension/traction rules, mounted cameras, carried passengers, and authority-island transfer. Ragdolls have bounded active lifetimes before sleep or simplification. These modules cannot bypass the general snapshot, streaming, and authority contracts.
#Assistant and automation interface
Expose documented tools for listing world content, querying schemas, reading entities, proposing transactions, compiling, creating preview sessions, inspecting logs/metrics, capturing a frame, and running scripted playtests. Read operations and mutation operations are distinct. All mutations use the same permissions, validation, version checks, and audit log as the editor.
A build request follows intent → bounded plan → source patch → validation/build → isolated playtest → visual/performance inspection → accepted transaction → publication when requested. Provider/model choice is configurable. Runtime frames never wait on this loop.
Keep a durable task record with requested scope, source revision, generated artifacts, tool results, and current status. An interrupted assistant resumes by reading state rather than blindly replaying writes. Content text, player chat, imported files, and generated output are data, not tool authorization.
Agent playtesting uses a normal scoped player identity in a test room, with actions exposed through the same input layer. Observation reports the room, engine/content revision, camera, asset readiness, and measured performance. A screenshot of an unloaded placeholder is not reported as a successful finished build.
#Deployment and operations
#Initial topology
Deploy static client/editor bundles to a CDN, an API/coordinator service behind TLS, one region of room relays, optional headless simulation workers, PostgreSQL, object storage, and bounded build workers. Local development uses the same package interfaces with local stores and containers. Hosting adapters avoid embedding a particular vendor in simulation code.
Room routing selects an existing compatible instance or starts one, with player cap and region policy. A room process has a fenced lease and generation. Health includes event-loop lag, tick time, queue size, durable commit latency, reconnect rate, and memory. Do not declare a room healthy merely because its socket listener responds.
Graceful deployment stops new admissions, announces drain, checkpoints, hands off or closes recoverably, and then terminates. Pin old engine bundles until all pinned rooms have ended or migrated. Durable Objects or another hosted relay may be added behind the coordinator/journal interface after workload tests; hibernation benefits depend on actual traffic and are not assumed for an always-ticking room.
#Security boundaries
Use short-lived, audience-scoped room tickets. Bind write privileges to authenticated sessions and world roles. Validate origin on browser session establishment; protect authoring routes against cross-site requests; enforce rate and size limits. Keep secrets in server services, never world bundles or creator scripts.
Untrusted asset parsing runs in isolated build workers with time/memory bounds. Uploaded content gets a type/signature check and output validation. Source maps and private world content are distributed only to authorized users. The engine does not send invisible entities or private inventory to unauthorized recipients.
Multi-tenant creator hosting is a later gate because hostile scripts, shaders, assets, and costs need isolation. A single-owner deployment can ship earlier with trusted authors, but that scope must be explicit in product and deployment configuration.
#Observability and support
Attach world, release, room generation, connection generation, place, authority epoch, tick, and transaction IDs to relevant diagnostics. Preserve privacy by default: log identifiers and bounded metadata, not authentication tokens or unrestricted player messages.
The inspector shows CPU/GPU frame timing, per-system tick cost, entities by state, draw calls, triangles, GPU/CPU memory, network ingress/egress, interpolation delay, correction distance, queue depth, journal lag, and asset residency. Device-loss and script-fault reports include reproducible configuration.
A support bundle contains the manifest, anonymized event trace where permitted, timing samples, and reproduction steps. Replays require consent when they contain private gameplay or chat. Retention and export behavior are explicit.
#Performance and capacity targets
These are initial benchmark targets, not achieved measurements. Milestone zero selects named hardware/browser configurations and stores their specifications with results. Compare cold/warm cache separately and report p50/p95/p99 where appropriate.
| Metric | Initial target fixture | Measurement |
|---|---|---|
| Desktop frame time | p95 at or below 16.7 ms at 1080p on the selected midrange reference machine | Ten-minute walkthrough, GPU and CPU timings, no devtools overhead |
| Mobile frame time | p95 at or below 33.3 ms on the selected supported phone | Touch walkthrough with sustained thermal load |
| Simulation | p95 below 8 ms for 30 Hz, p99 below 16 ms in the baseline fixture | Per-system timing with 16 players and 128 active bodies |
| First control | Within 5 s cold on a shaped 20 Mbps/80 ms connection for the small fixture | Navigation to responsive movement; script/asset bytes recorded |
| Critical download | At most 8 MiB compressed for that fixture's initial controllable state | Engine, WASM, collision, essential art; optional assets excluded and reported |
| Network | Target below 30 KiB/s downstream per player in the 16-player baseline, excluding join/assets | Average and peaks; no implied scaling to dense crowds |
| Live property edit | p95 visible within 1 s after accepted commit on a 100 ms RTT test | Both clients report the same revision; heavy builds reported separately |
| Reconnect | Resume within 5 s after network restoration in a warm room | No duplicate body/reward; full baseline may take longer and is measured |
| Memory | No monotonic growth across 100 place crossings and repeated live edits | CPU heap, array buffers, GPU/resource census separately |
| Durability | Zero lost acknowledged durable transactions under crash tests | Compare durable log/state after repeated forced process termination |
A bandwidth estimate should use encoded bytes × updates per second × visible entities × recipients, plus headers and spikes. Measure actual traffic before pricing. GPU memory includes decompressed textures and render targets, not just download size. World size, room concurrency, and visible density are separate capacity axes.
When budgets fail, record the dominant cost and reduce unnecessary work before changing architecture: culling, sleeping, LOD, interest scope, batching, allocation, and content budgets. Separate benchmark improvements from claims about arbitrary user worlds.
#Validation strategy
Core tests cover entity generations, query mutation barriers, change cursors, snapshot consistency, migration, deterministic replay, and fixed-step overload. Physics fixtures include stairs, slopes, doorways, moving platforms, stacked bodies, high-speed collision, sleep/wake, and restore.
Network tests include delayed/duplicated application messages, disconnect during snapshot, reconnect after journal compaction, stale owner after partition, simultaneous pickup, host death mid-portal, old-tab resurrection, lost edit notification, malformed packet, and backpressure. TCP packet loss is tested through network shaping; application reordering/duplication is tested in the protocol harness rather than incorrectly assuming TCP delivers out of order.
Persistence tests kill processes before/after every commit/ACK boundary and compare recovered state. Editor tests combine concurrent edits, undo after another writer, script migration failure, asset failure, and content rollback with newer player state.
Renderer tests combine tolerant reference images, shader validation, GPU diagnostics, and real-device walkthroughs. Do not require bit-identical images across GPU vendors. Test context/device loss, resolution changes, transparent sorting, skeletal attachments, portal clipping, and resource disposal.
Each milestone adds a repeatable demo fixture and a small set of meaningful acceptance tests. Bots load-test protocol/state, while real rendered clients test graphics and presentation. A bot-only test cannot establish browser frame rate or perceived motion quality.
#Repository and public interfaces
Use one workspace with enforceable package boundaries. Initially create only packages needed by the current milestone; the target layout describes ownership, not a requirement to scaffold empty directories.
apps/player/ Browser player shell
apps/editor/ Browser authoring environment
services/control/ Worlds identities releases authoring API
services/relay/ Sessions leases journal routing
services/sim-host/ Trusted headless simulation
services/build-worker/ Asset and behavior compilation
packages/schema/ World component command and wire definitions
packages/core/ ECS scheduler lifecycle events
packages/math/ Coordinate conventions deterministic helpers
packages/simulation/ Input commands authority and system scheduling
packages/physics/ Backend contract controller and adapters
packages/render/ Presentation protocol and resource ownership
packages/render-webgpu/ GPU backend shader compiler and render graph
packages/net/ Codecs client state machine replication recovery
packages/world/ Place graph streaming prefabs migrations
packages/behavior/ Script VM SDK budgets and capabilities
packages/assets/ Manifests importers runtime asset service
packages/authoring/ Transactions history undo and live application
packages/ui/ Input HUD audio and accessibility integration
packages/agent-tools/ Scoped observations mutations and test tools
packages/testkit/ Deterministic clocks fault injection fixtures
tools/cli/ Dev validate build playtest publish migrate
games/engine-zoo/ Small fixtures for each capability
games/darkwind/ First substantial game
games/cooperative-puzzle/ Independent second-game validation
docs/ Specifications decisions and operationsThe SDK exports versioned component, behavior, world, input, interaction, rendering-extension, and authoring APIs. Never expose internal storage layout as a supported content API. Generated reference documentation and examples ship with each engine pin. A world can inspect its capabilities and choose a supported fallback instead of guessing engine internals.
#Delivery strategy and effort
The critical path is schema → ECS/simulation → renderer/physics contracts → single-place play → relay authority/recovery → durable state → live authoring → reusable game API → compatibility and operations. Early fixtures validate architecture; they do not remove later scope.
Plan in engineering effort, with calendar forecasts revised after the first three milestones. A useful planning envelope is 40–75 engineering person-weeks to a robust creator preview, another 35–70 to engine version 1, and another 60–130 for advanced terrain, broad compatibility, rich simulation, and an owned physics replacement. These ranges include substantial integration/testing work but exclude a large finished game's content library and community platform. They are estimates, not commitments or Spawn staffing data.
A focused three-to-five-person team might target a preview in roughly four-to-eight months and version 1 in nine-to-eighteen months, subject to dependency bottlenecks and specialist availability. One developer should plan a multi-year program for broad parity. AI tools can accelerate implementation and content iteration; they do not remove GPU validation, network failure testing, or design work.
Needed disciplines are engine/runtime, graphics, networking/backend, tools/frontend, and content/technical art, with recurring QA and deployment coverage. One person may cover several roles, but the roadmap cannot assume all roles advance simultaneously.
#Risks and decisions to revisit
| Risk | Consequence | Planned response |
|---|---|---|
| Treating indexed Spawn details as current truth | Recreating an obsolete or misunderstood design | Keep evidence ledger; validate our invariants independently |
| Custom renderer consumes the whole schedule | Attractive demo without a usable engine | Ship a narrow PBR feature set, enforce milestone gates, defer advanced passes |
| Cross-owner physics has conflicting writers | Jitter, duplicated ownership, divergent state | Authority islands and trusted-host contact rules |
| Browser hosts suspend or disappear | Frozen worlds and data loss | Coordinator fencing, checkpoints, explicit pause or trusted fallback |
| General scripts undermine deterministic replay | Divergent recovery and exploits | Restricted hooks, recorded external results, VM gate |
| Unbounded content or crowds | Memory exhaustion and fanout cost | Per-world budgets, interest limits, admission, measured tiers |
| Live editing mixes definition and state | Lost inventory or broken sessions | Separate stores, transaction barriers, state migrations |
| Asset production becomes inconsistent | Large downloads and incoherent worlds | Modular kit, importer validation, budgets, provenance |
| Multi-browser GPU behavior diverges | Device-specific failures | Named support matrix, fallback placement, reference scenes |
| Every platform feature is attempted at once | No complete usable milestone | Preview/version 1/extended gates with dependency order |
Revisit the worker layout after the first measured scene, the binary protocol after real replication traces, the physics replacement after the adapter fixture suite, and hosting vendors after representative room and egress measurements. These checkpoints authorize technical refinement, not silent removal of the engine objective.
#Definition of completion
The engine program reaches version 1 when a new world can be authored, validated, published, joined by multiple real clients, edited in development while running, upgraded, recovered after host/service failure, and restored from backup through documented tools. Both authority profiles pass their declared guarantees. Supported devices meet the reference budgets. Darkwind and an unrelated second game consume the same public SDK.
Extended Spawn-like parity is complete only when the separately listed terrain, advanced portals, physics modules, creator isolation, AI authoring, and compatibility capabilities pass their own roadmap gates. A successful screenshot, single-player walkthrough, or optimistic capacity estimate cannot substitute for those outcomes.