Files
open-wc/docs/modules/m2-animated-instance-materializer.md
T

12 KiB

M2 Animated Instance Materializer

Metadata

Field Value
Status Implemented extraction
Target/work package M03 / M03-RND-M2-ANIMATED-INSTANCE-MATERIALIZER-001
Owners Animated M2 duplicate/batch construction, render settings, playback startup and attachment
Last verified Worktree work/sindo-main-codex/m03-m2-animated-instance-materializer, 2026-07-18
Profiles/capabilities Imported GLB and native experimental animated M2 instances

Purpose

Materialize one ordered animated M2 build batch on the main thread. The service duplicates an accepted prototype, preserves historical names and transforms, applies visibility/shadow settings recursively, starts native/imported playback, attaches a non-empty batch and returns detached native diagnostic entries.

Non-goals

  • Plan build batches, advance job cursors or consume render budgets.
  • Load, finalize, select or cache animated prototypes.
  • Select animations or implement native animator deformation.
  • Format logs, normalize paths, assign Editor owners or clean up tile roots.
  • Materialize static M2 MultiMesh batches.

Context and boundaries

flowchart LR
    Loader[StreamingWorldLoader adapter] --> Materializer[M2AnimatedInstanceMaterializer]
    Prototype[Accepted animated prototype] --> Materializer
    Plan[Transforms and batch slice] --> Materializer
    Materializer --> Playback[M2AnimationPlaybackController]
    Materializer --> Finalizer[M2AnimatedSceneFinalizer traversal]
    Materializer --> Batch[Attached animated batch]
    Materializer --> Diagnostics[Detached diagnostic entries]

Allowed dependencies are Godot Node/Node3D/GeometryInstance3D APIs and the accepted animated finalizer and playback services. Resource loading, files, workers, caches, scheduler policy, Editor ownership and MultiMesh are forbidden.

Public API

Symbol Kind Purpose Thread/lifetime Errors
materialize_batch(parent, path, prototype, transforms, start, count, serial, visibility_end, visibility_margin, cast_shadows, native_script, collect_diagnostics) Command/query Build, start and attach one ordered animated batch Main thread; borrowed inputs, parent owns result Invalid/empty input or all failed duplicates returns {}

Inputs and outputs

Direction Contract/data Producer Consumer Ownership Thread/lifetime
Input M2 parent root Loader build job Batch attachment Borrowed Node3D Tile/job lifetime
Input Relative path, start/count and serial Batch planner/loader adapter Names, phase and slice Copied scalars One call
Input Accepted animated prototype Prototype cache Duplicate source Borrowed Node3D Cache-owned
Input Ordered transforms Placement grouping/build job Instance transforms Borrowed Array Job lifetime
Input Visibility/shadow settings Renderer configuration Recursive render mutation Copied scalars One call
Input Native animator Script identity Loader composition Playback controller Borrowed Script Application lifetime
Output batch_root Materializer Parent SceneTree and loader Editor-owner adapter Parent-owned Node3D Tile lifetime
Output native_diagnostics entries Playback controller/materializer Loader log adapter Caller-owned Array/Dictionaries Debug call

Side effects are Node duplication, instance naming/transform assignment, recursive geometry mutation, playback mutation and SceneTree attachment. The service retains no batch, prototype, transform or diagnostic references.

Data flow

flowchart TD
    Slice[Ordered transform slice] --> Duplicate[Duplicate prototype with signals, groups and scripts]
    Duplicate --> Identity[Assign historical name and transform]
    Identity --> Render[Apply visibility margin and shadow recursively]
    Render --> NativeCopy[Copy native animator runtime fields]
    NativeCopy --> AttachInstance[Attach duplicate to detached batch]
    AttachInstance --> Players[Inventory AnimationPlayers]
    Players --> Start[Start deterministic native/imported playback]
    Start --> More{More slice entries?}
    More -->|yes| Duplicate
    More -->|no, non-empty| AttachBatch[Attach batch to supplied parent]
    Start --> Diagnostics[Tag detached states with instance index]

Lifecycle/state

stateDiagram-v2
    [*] --> Validating
    Validating --> Empty: invalid input
    Validating --> Building: valid slice
    Building --> Building: next successful duplicate
    Building --> Empty: no successful duplicates
    Building --> Attached: non-empty batch
    Empty --> [*]
    Attached --> [*]: parent/tile owner releases subtree

The RefCounted service is stateless; lifecycle labels describe each batch call.

Main sequence

sequenceDiagram
    participant L as StreamingWorldLoader
    participant M as M2AnimatedInstanceMaterializer
    participant F as M2AnimatedSceneFinalizer
    participant P as M2AnimationPlaybackController
    participant R as M2 parent root
    L->>M: materialize_batch(slice, prototype, render settings)
    loop ordered instance
        M->>M: duplicate, name, transform, render settings
        M->>P: copy native animator fields
        M->>F: animation_players_in_subtree(duplicate)
        M->>P: start_instance_playback(path, index, players, debug)
    end
    M->>R: add_child(non-empty batch)
    M-->>L: batch root and indexed diagnostics
    L->>L: format logs and assign Editor owner

Dependency diagram

flowchart TB
    Loader[StreamingWorldLoader] --> Materializer[M2AnimatedInstanceMaterializer]
    Materializer --> Playback[M2AnimationPlaybackController]
    Materializer --> Finalizer[M2AnimatedSceneFinalizer]
    Materializer --> Engine[Node3D / GeometryInstance3D / SceneTree APIs]
    Loader --> EditorOwner[Editor ownership adapter]
    Loader --> BuildJob[Build cursor and budget]
    Materializer -. no dependency .-> Cache[Prototype/cache/load state]
    Materializer -. no dependency .-> MultiMesh[Static M2 materialization]

Ownership, threading and resources

  • Loader/build state borrows the accepted prototype and ordered transform Array.
  • Each successful duplicate becomes a child of the detached batch immediately.
  • A non-empty batch transfers to the supplied parent; the parent owns its lifetime.
  • A batch with no successful duplicates is queued for deletion and no reference returns.
  • Playback/finalizer services borrow each duplicate only during synchronous calls.
  • Returned diagnostic entries contain the stable instance index and a detached state.
  • All Node duplication, mutation and attachment is main-thread-only.

Errors, cancellation and recovery

Failure Detection Behavior Diagnostic Recovery
Null parent/prototype Entry guard Return {} without mutation Contract verifier Correct composition/cache state
Empty transforms or non-positive count Entry guard Return {} Contract verifier Planner supplies a non-empty slice
Duplicate is not Node3D Cast result Skip that entry and preserve order of successes Child-count contract Repair prototype scene root
Every duplicate fails Empty batch check Queue empty batch, return {} Empty-result contract Rebuild/import prototype
Shutdown during/after call Outside service Call is synchronous; loader owns cancellation and subtree release Shutdown regression Loader cancels job/releases parent

Transform bounds remain a planner/build-job precondition exactly as before the extraction; this service does not clamp or silently reorder an invalid slice.

Configuration and capabilities

Setting/capability Default Profile Runtime mutable Effect
Duplicate flags Signals + groups + scripts All No Preserves historical instance behavior
Visibility end/margin Loader renderer settings / chunk size All Yes, between calls Applied to every GeometryInstance3D descendant
Shadow mode Loader m2_cast_shadows All Yes, between calls Enables/disables descendant shadow casting
Native diagnostics Loader debug_streaming Debug Yes Collects indexed state only when requested

Persistence, cache and migration

No data is serialized and no cache/schema version changes. Editor owner assignment remains a loader concern after attachment, so generated-scene persistence behavior and migration remain unchanged.

Diagnostics and observability

  • The materializer emits no logs, metrics or debug views.
  • Native state remains detached and is tagged with the absolute instance index.
  • Loader preserves the existing normalized-path M2_NATIVE_ANIMATOR log text.
  • No correlation ID is introduced; path/index remains the existing identity.

Verification

  • verify_m2_animated_instance_materializer.gd covers invalid input, names, order, transforms, recursive visibility/margin/shadows, playback, native field references, indexed diagnostics, prototype immutability and ownership boundaries.
  • Playback/finalizer/pipeline/build/prototype/shutdown/material/facade/internal- access regressions protect adjacent behavior.
  • Fidelity evidence is exact extraction of existing flags/order/settings/calls; no original-client visual comparison or proprietary asset result is claimed.
  • Performance budget: 1,000 synthetic Node3D instances under one second.

Extension points

A later facade-owned animated presentation command may supply the same explicit batch contract. Async SceneTree mutation, callbacks and a generic scene factory are intentionally excluded until measurements show a need.

Capability status

Capability Status Evidence Gap/next step
Ordered animated instance/batch materialization Implemented extraction Synthetic batch contract verifier Proprietary asset traversal pending
Recursive visibility/shadow settings Implemented extraction Nested geometry fixture Visual distance/shadow comparison pending
Native/imported playback startup Delegated to implemented controller Playback + materializer verifiers Full WoW animation-state mapping pending
Editor persistence Existing loader-owned Source boundary and editor helper Editor integration fixture remains separate

Known gaps and risks

  • The existing build planner must continue to guarantee valid transform bounds.
  • Default animation selection and native deformation retain their documented gaps.
  • No private asset, paired original-client, descriptor-pressure, leak or p95/p99 run exists.
  • Recursive render mutation remains proportional to duplicate subtree size.

Source map

Path Responsibility
src/render/m2/m2_animated_instance_materializer.gd Duplicate, render mutation, playback startup and non-empty batch attachment
src/render/m2/m2_animation_playback_controller.gd Phase, selection and native/imported playback mutation
src/render/m2/m2_animated_scene_finalizer.gd AnimationPlayer inventory for each duplicate
src/scenes/streaming/streaming_world_loader.gd Build adapter, diagnostic formatting and Editor ownership
src/tools/verify_m2_animated_instance_materializer.gd Batch/render/playback/boundary/timing regression