mittens-engine 0.7.0

A Vulkan and OpenXR scene engine with ECS, reactive signals, and Meow Meow scripting
// bisket-vr-debug scene
//
// Headless verification scene for the head-driven AVC redesign.
//
// Two bisket avatars share the world:
//   1. REFERENCE — no AVC, no driver. Bones sit at GLTF rest pose. The
//      "what would natural FK do" baseline.
//   2. AVC-DRIVEN — full AVC with spine FABRIK wired. Its driven_t is a
//      plain TransformComponent that the harness (bisket-vr-debug.rs)
//      mutates each pose to simulate HMD movement, with NO OpenXR or
//      InputXR in the loop.
//
// The harness:
//   - Spawns the scene, ticks GLTF to instantiate armatures.
//   - Scripts driven_t through a fixed sequence of poses.
//   - Per pose, samples world Y/Z of hips → spine → chest → upper_chest →
//     neck → head bones on both avatars, and prints a diff table.
//
// No camera renders are required, but a C3D is kept so AVC's camera_bone
// reparent logic doesn't emit warnings.
//
// To run:
//   cargo run --release --example bisket-vr-debug

RendererSettings.msaa_off() {
    window_size(320, 240)
}

BGC.rgba(0.40, 0.42, 0.50, 1.0)
AL.rgb(0.25, 0.25, 0.30)

ED {
    // --- REFERENCE avatar (left, x=-1.2) ---
    // Plain GLTF subtree.  No AVC, no input.  Bones stay at FK rest pose
    // for the lifetime of the harness, so they form the comparison baseline.
    T.position(-1.2, 0.0, 0.0) {
        T {
            GLTF.new("assets/models/bisket.glb")
        }
    }

    // --- AVC-DRIVEN avatar (right, x=+1.2) ---
    // The OUTER T at +1.2 is just the world-space placement.  The INNER T
    // (initially at y=1.55) is `driven_t` — AVC reads it via parent_of(avc).
    // The harness emits UpdateTransform on this T each pose to simulate the
    // HMD moving, without needing OpenXR.
    T.position(1.2, 0.0, 0.0) {
        T.position(0.0, 1.55, 0.0) {
            AVC {
                head_bone("J_Bip_C_Head")
                camera_bone("J_Bip_C_Head")
                hips_bone("J_Bip_C_Hips")
                left_hand_bone("J_Bip_L_Hand")
                right_hand_bone("J_Bip_R_Hand")
                left_upper_arm_bone("J_Bip_L_UpperArm")
                left_lower_arm_bone("J_Bip_L_LowerArm")
                right_upper_arm_bone("J_Bip_R_UpperArm")
                right_lower_arm_bone("J_Bip_R_LowerArm")
                initial_yaw(3.14159)
                hand_grip_rotation_left([-0.6408564, 0.29883623, 0.29883623, 0.6408564])
                hand_grip_rotation_right([-0.6408564, -0.29883623, -0.29883623, 0.6408564])

                T {
                    GLTF.new("assets/models/bisket.glb")
                }

                // Eye-offset T-wrapper, mirroring bisket-vr-demo.  The
                // C3D won't actually render anything we care about here
                // (no window loop), but its presence is what feeds the
                // head_target_offset into AVC.
                T.position(0.0, 0.08, 0.04) {
                    C3D {}
                }

                XRHand.new(true, Left, Grip)
                    .laser_from_avatar_finger("[name='J_Bip_L_Middle1']", "[name='J_Bip_L_Middle2']", "[name='J_Bip_L_Middle3']") {
                    T { Pointer {} }
                }
                XRHand.new(true, Right, Grip)
                    .laser_from_avatar_finger("[name='J_Bip_R_Middle1']", "[name='J_Bip_R_Middle2']", "[name='J_Bip_R_Middle3']") {
                    T { Pointer {} }
                }
            }
        }
    }
}