+ /* walk/run */
+ mdl_keyframe apose[32], bpose[32];
+ skeleton_sample_anim( sk, w->anim_walk, t*walk_norm, apose );
+ skeleton_sample_anim( sk, w->anim_run, t*run_norm, bpose );
+
+ skeleton_lerp_pose( sk, apose, bpose, l, apose );
+
+ /* idle */
+ skeleton_sample_anim( sk, w->anim_idle, vg.time*0.1f, bpose );
+ skeleton_lerp_pose( sk, apose, bpose, 1.0f-idle_walk, apose );
+
+ /* air */
+ skeleton_sample_anim( sk, w->anim_jump, vg.time*0.6f, bpose );
+ skeleton_lerp_pose( sk, apose, bpose, animator->fly, apose );
+
+ /* sit */
+ if( animator->sit_t > 0.0f ){
+ f32 sit_norm = (f32)(w->anim_sit->length-1)/30.0f,
+ st = vg_minf( 1.0f, animator->sit_t );
+ skeleton_sample_anim( sk, w->anim_sit, st*sit_norm, bpose );
+
+ v4f qy,qp;
+ f32 *qh = bpose[av->id_head-1].q;
+ q_axis_angle( qy, (v3f){0.0f,1.0f,0.0f}, animator->yaw*0.5f*st );
+ q_axis_angle( qp, (v3f){0.0f,0.0f,1.0f}, animator->pitch*st );
+ q_mul( qy, qh, qh );
+ q_mul( qh, qp, qh );
+ q_normalize( qh );
+
+ qh = bpose[av->id_chest-1].q;
+ q_axis_angle( qy, (v3f){0.0f,1.0f,0.0f}, animator->yaw*0.5f*st );
+ q_mul( qy, qh, qh );
+ q_normalize( qh );
+
+ skeleton_lerp_pose( sk, apose, bpose, vg_minf(1.0f,st*10.0f), apose );
+ }
+
+ if( animator->outro_type ){
+ struct skeleton_anim *anim = player_walk_outro_anim(animator->outro_type);
+
+ f32 outro_length = (f32)anim->length / anim->rate,
+ outro_time = animator->outro_t*outro_length;
+
+ skeleton_sample_anim_clamped( sk, anim, outro_time, bpose );
+ skeleton_lerp_pose( sk, apose, bpose, animator->outro_t*10.0f,
+ pose->keyframes );
+
+ if( animator->outro_type == k_walk_outro_drop_in ){
+ m4x3f transform, inverse;
+ q_m3x3( pose->root_q, transform );
+ v3_copy( pose->root_co, transform[3] );
+ m4x3_invert_affine( transform, inverse );
+
+ v3f anchored_pos;
+ m4x3_mulv( inverse, animator->foot_anchor, anchored_pos );
+
+ v3_lerp( pose->keyframes[ av->id_ik_foot_r-1 ].co, anchored_pos,
+ 1.0f-animator->commit_t,
+ pose->keyframes[ av->id_ik_foot_r-1 ].co );