Skip to content

[feat] 33 P2: animated, functional pack items (doors that open, no autoplay) - #259

Merged
AlexZ005 merged 3 commits into
feat/1.19from
feat/33-anim-core
Oct 2, 2026
Merged

AlexZ005 merged 3 commits into
feat/1.19from
feat/33-anim-core

Conversation

@AlexZ005

@AlexZ005 AlexZ005 commented Oct 1, 2026

Copy link
Copy Markdown
Collaborator

Roadmap 33, lane 33-anim-core: contract P2, animated, functional pack items. This is the core half of K4 ("if its a door it should be functional ... not randomly plays animation or in loop").

What it does

  • Nothing autoplays. Placing an animated GLB used to start its first clip and loop it forever. Now the clip is selected, not playing, until someone presses play. Animated imports also land at the drop point, which this path used to ignore.
  • behavior on a pack item (door | toggle | oneshot | loop, triggers click | proximity | knock). A peer in Edit always sees the rest pose. A trigger works in Interact/Play: the desktop click, the Play tap, and the VR laser/poke, which all go through moduleSDK's one click dispatch. Proximity is 1.5 m. A knock is a VR hand at >= 0.6 m/s.
  • State replicates as one new behavior message {uuid, on, at, from, n}, latest-wins on sessionNow(). It has a wireValidate shape and is ROOM_SCOPED. Every peer derives the pose from the stamp. A late joiner gets behaviorState on its objectfile. The state is runtime only: never saved, never undone.
  • The leaf collider follows. The frame becomes custom slab colliders with the doorway cut out, through the wall's depth. Each moving node gets a kinematic box that follows it. An open door lets the walker through and a shut one stops it, while a sim runs.
  • A sound per trigger: new game sounds door gate slide lever lid.
  • The Explorer shows a ▶ "animated" badge on cards and list rows.
  • The Animation panel previews a clip in Edit locally: nothing is sent, nothing is saved, and the item goes back to rest.
  • api.behavior {list, state, trigger} for modules.
  • Animated imports also carry userData.lod on objectfile, the save and undo, for 33-lod-editor.
  • A sim start's "simulate the selection" fallback never picks a functional item.

Contract notes for the pack lanes are at the top of the handover. anim-kit's 19 interactive-kit items were checked against the runtime offline.

Proof

  • pack-behavior (new, 51 checks, two peers + a late joiner), driving the real Explorer path with a routed pack and a gltf-transform test door (tests/e2e/fixtures/test-door.glb):
    • placed and still;
    • Edit stands down;
    • a REAL click in Interact opens it, with sound;
    • B sees it open in Interact and shut in Edit;
    • the capsule passes an open door and is stopped by a shut one;
    • counterfactual: with the doorway not cut, an open door is a wall;
    • the save holds the spec and no state;
    • the late joiner gets the same stamp;
    • the preview sends nothing;
    • wire validation, api.behavior, and a slow vs fast knock.
  • vitest behaviorCore (18).
  • Touched suites green: animated-models 15/0 and animation-persist 23/0 (both now press play first, because there is no autoplay), game-audio 26/0 (25 sounds), packs-explorer 10/0.
  • svelte-check 333/47 (= base, measured on c7018be), vitest 396/396, check-storage clean, npm run build green.

Owed on device

A door in a Quest (laser click, poke, knock speed), the sounds' character, the badge in non-dark themes, and walking up to a proximity sliding door for real.

Forks taken (QUESTIONS-33-anim-core.md)

  • Door state lasts the session: Edit shows the rest pose and Interact shows the shared state again.
  • Old saves with playing: true keep playing.
  • Proximity opens on entering and closes on leaving.
  • A desktop click counts as the knock.

🤖 Generated with Claude Code

AlexZ005 and others added 3 commits October 1, 2026 21:00
…op), no autoplay

- behaviorCore.js (pure, vitest 18): normalizeBehavior, the pose as a pure function of
  {on, at, from, n} + the session clock, nextState, frameSlabs/passageThrough (the doorway
  cut out of a one-piece frame, through the wall's depth)
- packBehavior.js: per-frame pose driver (rest pose in Edit whatever the shared state),
  a core click handler in moduleSDK's one dispatch (desktop Interact click, Play tap, VR
  laser/poke), proximity (1.5 m) and knock (VR hand >= 0.6 m/s) triggers, the `behavior`
  wire message (latest-wins on sessionNow), a kinematic box per moving node that follows
  the swing while a sim runs + the frame as custom slab colliders, a local Animation-panel
  preview (never sent/saved), the per-item sound
- animatedImports: NOTHING AUTOPLAYS on placement any more (the first clip used to start
  and loop); behavior roots skip the transport; spec (+ live state on the wire, + the
  lod-editor's userData.lod) ride objectfile, the save snapshot and the undo entry
- fileHandler: animated imports land at the drop point; opts.behavior from the pack row
- packs/Explorer/explorerDrop: the row's spec travels to placement; an "animated" badge on
  cards and list rows
- gameSfx: + door gate slide lever lid; wireValidate `behavior` shape; ROOM_SCOPED;
  vrGameInput treats behavior roots as clickable; api.behavior {list, state, trigger}
- suites: pack-behavior (new; test-door.glb built with gltf-transform), animated-models and
  animation-persist press play first now, game-audio expects 25 sounds

WIP at the budget checkpoint: pack-behavior ran 41 pass / 8 fail before the priming fix in
this commit. 7.2 (the first walk resolved on the plane tier: charController's lazy physics
import; primed now, not re-run). 7.6 (the reopen click on the frame post did not toggle)
cascades into 8.2/9.1/11.2/13.1/13.2 - next window's first job. Counterfactuals already
green: 7.7 (uncut frame = a wall when open), 2.3/12.1 (no autoplay), 14.1 (slow hand).
svelte-check 333/47 (= base), vitest 396/396, check-storage clean.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…behavior

- PACKS.md: the behavior contract (types, triggers, the no-autoplay rule, shared state,
  frame + moving parts + collider follow, authoring notes, the Explorer badge)
- MODULES.md: api.behavior list/state/trigger and the five item sounds

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…t play schedules the clip

- physics: with nothing dynamic, a sim start simulated the (sticky) selectedObject — the
  door just placed. It fell over and every Interact click on it became a carry (the
  pack-behavior 7.x flake). Functional items (userData.behavior) are skipped; a door-only
  scene now gets the existing "Nothing to simulate" toast.
  Counterfactual: pack-behavior 7.0a (the door dynamic) and 7.3/7.7 go red without it.
- animatedImports: with registration no longer autoplaying, nothing scheduled the action
  when `playing` later turned true (a press, or a restored playing save) — the state said
  playing and nothing moved. setAnimationState schedules it on the first play.
  Counterfactual: animated-models "clip animates on A/B", animation-persist "animates
  before saving / after the round trip" go red without it.
- packBehaviorDebug grows click diagnostics (clicks, lastClick {mesh, result}).
- suites: pack-behavior primes the walker, adds a real dynamic crate + 7.0a/7.0b, samples
  the preview window (10.1); animation-persist's panel section starts from a playing clip.

Battery (vite inside e2e-slot, PEER_CONFIG): pack-behavior 51/0, animated-models 15/0,
animation-persist 23/0, game-audio 26/0, packs-explorer 10/0. svelte-check 333/47 (= base),
vitest 396/396, check-storage clean, npm run build green.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant