Parent: #126
Corresponds to EN-032 in docs/tickets.md
Problem
Model/world loads are synchronous and handle APIs assume data is immediately resident. Large scenes need asynchronous IO, decode, cook-chunk reads, GPU upload, world-cell activation, and eviction without blocking the game/render thread. This must remain simple at the TypeScript surface.
Outcome
Handle-based asynchronous asset and world streaming with priorities, cancellation, memory budgets, stable placeholders, progress/error reporting, and deterministic world-cell activation.
Public API contract
Design one small API shape compatible with Perry—for example:
loadModelAsync(pathOrAssetId) -> AssetHandle<Model>;
- handle states
Queued | Loading | Ready | Failed | Cancelled;
isReady, getError, getProgress, retain/release or scoped ownership;
- optional callback/event or polling that does not allocate heavily per frame;
- synchronous development convenience may remain, implemented on top or clearly documented as blocking.
Exact naming is open, but callers may create scene nodes immediately with a placeholder and receive an atomic swap when ready. No raw pointers or JS-only Promises that cannot work in native Perry builds.
Runtime pipeline
- Resolve logical asset ID and platform variant from cooked manifest.
- Prioritized IO on worker(s), supporting loose files and package ranges.
- Decode/decompress/validate off the render thread.
- Stage bounded GPU uploads and resource-table updates.
- Publish ready state only after all required GPU/resources are safe to reference.
- Retire/evict after reference loss and GPU completion fences.
Backpressure must bound queued bytes, decode memory, staging memory, and GPU uploads per frame.
World streaming
- Partition world data into cells/chunks with dependency lists and coarse bounds.
- Load/unload by camera/interest volumes plus hysteresis and priorities.
- Separate data readiness from activation; activate a cell atomically at a frame boundary.
- Keep stable entity/asset IDs across unload/reload.
- Generate or consume HLOD/coarse proxies so missing fine cells do not reveal holes.
- Physics/nav/audio activation order must be explicit and testable.
Failure and cancellation
- Missing/corrupt/version-mismatched assets enter
Failed with an actionable message and render a diagnostic placeholder.
- Cancellation releases queued/intermediate resources without racing a completion callback.
- Device loss/recreation has a documented reupload/reload policy.
- A late result cannot populate a handle whose generation was reused.
Acceptance criteria
Likely files
- new asset manager under
native/shared/src/
native/shared/src/models*.rs, textures.rs, staging.rs, renderer resource tables
src/models/, src/world/loader.ts, src/world/render.ts
- platform file/fetch adapters under
native/*/
- cooked asset format from the cooker issue
Non-goals
- General-purpose task runtime exposed to games.
- Network multiplayer replication.
- Runtime mesh simplification.
Dependencies
Parent: #126
Corresponds to EN-032 in
docs/tickets.mdProblem
Model/world loads are synchronous and handle APIs assume data is immediately resident. Large scenes need asynchronous IO, decode, cook-chunk reads, GPU upload, world-cell activation, and eviction without blocking the game/render thread. This must remain simple at the TypeScript surface.
Outcome
Handle-based asynchronous asset and world streaming with priorities, cancellation, memory budgets, stable placeholders, progress/error reporting, and deterministic world-cell activation.
Public API contract
Design one small API shape compatible with Perry—for example:
loadModelAsync(pathOrAssetId) -> AssetHandle<Model>;Queued | Loading | Ready | Failed | Cancelled;isReady,getError,getProgress,retain/releaseor scoped ownership;Exact naming is open, but callers may create scene nodes immediately with a placeholder and receive an atomic swap when ready. No raw pointers or JS-only Promises that cannot work in native Perry builds.
Runtime pipeline
Backpressure must bound queued bytes, decode memory, staging memory, and GPU uploads per frame.
World streaming
Failure and cancellation
Failedwith an actionable message and render a diagnostic placeholder.Acceptance criteria
Likely files
native/shared/src/native/shared/src/models*.rs,textures.rs,staging.rs, renderer resource tablessrc/models/,src/world/loader.ts,src/world/render.tsnative/*/Non-goals
Dependencies